M .builds/alpine.yml => .builds/alpine.yml +6 -10
@@ 1,19 1,15 @@
-image: alpine/3.15
+image: alpine/edge
arch: x86_64
packages:
- gcc
- git
- - meson
- - ninja
- - python3
- - py3-pip
- - py3-click
- - py3-mako
+ - make
+ - scdoc
sources:
- https://git.sr.ht/~fsx/cbare
tasks:
- - python: |
- pip install parsimonious
- build: |
cd cbare
- ./dorelease.sh
+ CCLD=gcc make check
+ ./baretest
+ ./utf8test
M .builds/archlinux.yml => .builds/archlinux.yml +5 -11
@@ 1,20 1,14 @@
image: archlinux
packages:
- - gcc
- clang
- git
- - meson
- - ninja
- - python
- - python-pip
- - python-click
- - python-mako
+ - make
+ - scdoc
sources:
- https://git.sr.ht/~fsx/cbare
tasks:
- - python: |
- pip install parsimonious
- build: |
cd cbare
- ./dodebug.sh
- ./doanalyze.sh
+ CC=clang CCLD=clang make check
+ ./baretest
+ ./utf8test
A .builds/openbsd.yml => .builds/openbsd.yml +13 -0
@@ 0,0 1,13 @@
+image: openbsd/7.1
+packages:
+ - git
+ - gmake
+ - scdoc
+sources:
+ - https://git.sr.ht/~fsx/cbare
+tasks:
+ - build: |
+ cd cbare
+ CC=clang make check
+ ./baretest
+ ./utf8test
M .gitignore => .gitignore +8 -1
@@ 1,1 1,8 @@
-/build-*
+/baretest
+/utf8test
+/libcbare.so
+/libcbare.a
+/cbare.pc
+/cbare.3
+/notes.md
+*.o
D LICENSE => LICENSE +0 -21
@@ 1,21 0,0 @@
-MIT License
-
-Copyright (c) 2022 Frank Smit
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
A Makefile => Makefile +66 -0
@@ 0,0 1,66 @@
+.POSIX:
+.SUFFIXES: .o .c
+.PHONY: all clean check install uninstall
+
+VERSION=0.0.1
+PREFIX ?= /usr/local
+LIBDIR ?= $(PREFIX)/lib
+INCDIR ?= $(PREFIX)/include
+MANDIR ?= $(PREFIX)/share/man
+PCDIR ?= $(PREFIX)/share/pkgconfig
+
+CCLD ?= clang
+
+DEFAULT_CFLAGS := \
+ -std=c99 \
+ -Wall -Werror -Wextra -Wpedantic \
+ -Wno-unused-function
+
+all: libcbare.so libcbare.a cbare.3 cbare.pc
+
+check: baretest utf8test
+
+baretest: test/baretest.o src/alloc.o src/die.o libcbare.a
+ $(CCLD) $(LDFLAGS) test/baretest.o src/alloc.o src/die.o libcbare.a -o $@
+
+utf8test: test/utf8test.o src/die.o
+ $(CCLD) $(LDFLAGS) test/utf8test.o src/die.o -o $@
+
+libcbare.so: src/cbare.o
+ $(CCLD) $(LDFLAGS) src/cbare.o -shared -o $@
+
+libcbare.a: src/cbare.o
+ $(AR) rcs $@ src/cbare.o
+
+.c.o:
+ $(CC) -std=c99 $(CFLAGS) $(DEFAULT_CFLAGS) -I./src -c $< -o $@
+
+src/cbare.o: src/cbare.h
+src/die.o: src/die.h
+src/alloc.o: src/alloc.h src/die.h
+test/baretest.o: src/cbare.h src/alloc.h src/die.h
+test/utf8test.o: src/utf8.h src/die.h
+
+cbare.3: cbare.3.scd
+ scdoc < $< > $@
+
+cbare.pc: cbare.pc.in
+ sed -e 's:@prefix@:$(PREFIX):g' -e 's:@version@:$(VERSION):g' < $< > $@
+
+install: all
+ mkdir -p $(DESTDIR)/$(LIBDIR) $(DESTDIR)/$(MANDIR)/man3 $(DESTDIR)/$(PCDIR) $(DESTDIR)/$(INCDIR)
+ install -m644 libcbare.so $(DESTDIR)$(LIBDIR)/libcbare.so
+ install -m644 libcbare.a $(DESTDIR)$(LIBDIR)/libcbare.a
+ install -m644 src/cbare.h $(DESTDIR)$(INCDIR)/cbare.h
+ install -m644 cbare.3 $(DESTDIR)/$(MANDIR)/man3/cbare.3
+ install -m644 cbare.pc $(DESTDIR)/$(PCDIR)/cbare.pc
+
+uninstall:
+ rm $(DESTDIR)$(LIBDIR)/libcbare.so
+ rm $(DESTDIR)$(LIBDIR)/libcbare.a
+ rm $(DESTDIR)$(INCDIR)/cbare.h
+ rm $(DESTDIR)/$(MANDIR)/man3/cbare.3
+ rm $(DESTDIR)/$(PCDIR)/cbare.pc
+
+clean:
+ rm -vf *.a *.so *.o */*.o baretest utf8test cbare.3 cbare.pc
M README.md => README.md +17 -23
@@ 1,6 1,6 @@
# cbare
-[BARE][] encoder and decoder.
+cbare is an I/O agnostic C implementation of the [BARE][] message encoding.
Build status: [![builds.sr.ht status](https://builds.sr.ht/~fsx/cbare.svg)](https://builds.sr.ht/~fsx/cbare?)
@@ 13,51 13,45 @@ Schema DSL parser and code generator are in development.
## Building
-Install [Meson][].
-
-Setup your build:
+For shared and static libraries, package config, and man page:
```
-meson --werror --buildtype=release ./build --prefix /usr
+make
```
-(note: omit `--buildtype=release` for development)
-
-compile:
+You can use different compilers and linkers:
```
-meson compile -C ./build
+CC=cproc CCLD=gcc LDFLAGS='-fuse-ld=mold' make
```
-and run tests:
+Tests:
```
-meson test -C ./build
+make check
+./baretest && echo pass || echo fail
+./utf8test && echo pass || echo fail
```
## Installation
-Run:
-
```
-meson install -C ./build
+make install
```
-Or provide `--destdir` to install to a different directory:
+You can pass PREFIX or DESTDIR to make if you'd like:
```
-meson install -C ./build --destdir ./package-root
+mkdir ./tmp
+make DESTDIR=./tmp PREFIX=/usr install
```
+Uninstallation is similar:
-## Notes
-
-`bare_put_uint` and `bare_get_uint` are from [poolparty][].
-
-`bare_put_int` and `bare_get_int` are from Go's standard library.
+```
+make uninstall
+```
[BARE]: https://baremessages.org/
-[Meson]: https://mesonbuild.com/Quick-guide.html
-[poolparty]: https://github.com/andrewchambers/poolparty/blob/master/csrc/poolparty.c
D baretest.c.mako => baretest.c.mako +0 -297
@@ 1,297 0,0 @@
-<%!
-
-import textwrap
-
-def cval(v):
- if isinstance(v, (tuple, list)):
- items = ", ".join(map(cval, v))
- items = "\n".join(textwrap.wrap(
- items,
- width=70,
- expand_tabs=False,
- initial_indent="\t\t",
- subsequent_indent="\t\t",
- ))
- return f"{{\n{items}\n\t}}"
-
- return v
-
-%>\
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdbool.h>
-
-#include "alloc.h"
-#define BARE_CALLOC(num, size) ckalloc(size)
-#include "cbare.h"
-#include "die.h"
-#include "membuf.h"
-
-/* macros are used to report the correct line numbers */
-
-void
-_check(bool result, char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- if (!result) {
- die_va(msg, &args);
- }
- va_end(args);
-}
-\
-<%text>
-#define check1(result, msg, ...) \
- do { \
- char tmp[1024] = {0}; \
- char *prefix = "%s:%d: "; \
- strcat(tmp, prefix); \
- if ((strlen(prefix) + strlen(msg) + 1) > 1024) { \
- die("tmp[1024] is too small"); \
- } \
- strcat(tmp, msg); \
- _check(result, tmp, __FILE__, __LINE__, __VA_ARGS__); \
- } while (0)
-
-#define check(result, msg, ...) check1(result, msg, __VA_ARGS__, "\n")
-</%text>\
-
-<%text>
-#define bincheck(a, b, sz) \
- do { \
- uint8_t *ap = a; \
- uint8_t *bp = b; \
- bool result = memcmp(ap, bp, sz) == 0; \
- if (!result) { \
- printf("a:"); \
- for (size_t i = 0; i < sz; i++) { \
- printf(" %02x", (uint8_t) *ap); \
- ap++; \
- } \
- printf("\n"); \
- printf("b:"); \
- for (size_t i = 0; i < sz; i++) { \
- printf(" %x", (uint8_t) *bp); \
- bp++; \
- } \
- printf("\n"); \
- } \
- check(result, "%s", "a != b"); \
- } while (0)
-</%text>\
-
-static uint64_t
-buf_reader(struct bare_ctx *const ctx, void *const data, uint64_t nbytes)
-{
- if (!membuf_read((struct membuf *) ctx->buf, data, nbytes)) {
- ctx->error = BARE_ERROR_READ_FAILED;
- nbytes = 0;
- }
-
- return nbytes;
-}
-
-static uint64_t
-buf_writer(struct bare_ctx *const ctx, const void *const data, uint64_t nbytes)
-{
- membuf_write((struct membuf *) ctx->buf, data, nbytes);
- return nbytes;
-}
-
-% for name, test in tests.items():
-void test_${name}()
-{
- struct membuf buf;
- struct bare_ctx ctx;
-
- membuf_init(&buf, 1024);
- bare_init(&ctx, &buf, buf_reader, buf_writer);
-
-% for p in test.inputs:
-<% var = f"{p.name}_input" %>\
-% if p.type == 'uint':
- uint64_t ${var} = ${cval(p.value)};
- bare_put_uint(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_uint failed");
-% elif p.type == 'u8':
- uint8_t ${var} = ${cval(p.value)};
- bare_put_u8(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_u8 failed");
-% elif p.type == 'u16':
- uint16_t ${var} = ${cval(p.value)};
- bare_put_u16(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_u16 failed");
-% elif p.type == 'u32':
- uint32_t ${var} = ${cval(p.value)};
- bare_put_u32(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_u32 failed");
-% elif p.type == 'u64':
- uint64_t ${var} = ${cval(p.value)};
- bare_put_u64(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_u64 failed");
-% elif p.type == 'int':
- int64_t ${var} = ${cval(p.value)};
- bare_put_int(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_int failed");
-% elif p.type == 'i8':
- int8_t ${var} = ${cval(p.value)};
- bare_put_i8(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_i8 failed");
-% elif p.type == 'i16':
- int16_t ${var} = ${cval(p.value)};
- bare_put_i16(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_i16 failed");
-% elif p.type == 'i32':
- int32_t ${var} = ${cval(p.value)};
- bare_put_i32(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_i32 failed");
-% elif p.type == 'i64':
- int64_t ${var} = ${cval(p.value)};
- bare_put_i64(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_i64 failed");
-% elif p.type == 'f32':
- float ${var} = ${cval(p.value)};
- bare_put_f32(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_f32 failed");
-% elif p.type == 'f64':
- double ${var} = ${cval(p.value)};
- bare_put_f64(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_f64 failed");
-% elif p.type == 'bool':
- double ${var} = ${cval(p.value)};
- bare_put_bool(&ctx, ${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_bool failed");
-% elif p.type == 'string':
- char *${var} = ${cval(p.value)};
- bare_put_str(&ctx, ${var}, strlen(${var}));
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_str failed");
-% elif p.type == 'data':
- uint8_t ${var}[] = ${cval(p.value)};
- bare_put_data(&ctx, ${var}, ${len(p.value)});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_data failed");
-% elif p.type == 'fixed_data':
- uint8_t ${var}[] = ${cval(p.value)};
- bare_put_fixed_data(&ctx, (uint8_t *)${var}, ${len(p.value)});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_put_fixed_data failed");
-% endif
-% endfor
-
- uint8_t expect[] = ${cval(test.expect)};
- size_t expectsz = ${len(test.expect)};
- check(buf.size == expectsz, "%d != %d", buf.size == expectsz);
- bincheck(buf.data, expect, expectsz);
-
-% for p in test.inputs:
-<% var = f"{p.name}_output" %>\
-<% varsz = f"{p.name}_sz" %>\
-<% varin = f"{p.name}_input" %>\
-% if p.type == 'uint':
- uint64_t ${var};
- bare_get_uint(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_uint failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'u8':
- uint8_t ${var};
- bare_get_u8(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_u8 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'u16':
- uint16_t ${var};
- bare_get_u16(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_u16 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'u32':
- uint32_t ${var};
- bare_get_u32(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_u32 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'u64':
- uint64_t ${var};
- bare_get_u64(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_u64 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'int':
- int64_t ${var};
- bare_get_int(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_int failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'i8':
- int8_t ${var};
- bare_get_i8(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_i8 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'i16':
- int16_t ${var};
- bare_get_i16(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_i16 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'i32':
- int32_t ${var};
- bare_get_i32(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_i32 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'i64':
- int64_t ${var};
- bare_get_i64(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_i64 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'f32':
- float ${var};
- bare_get_f32(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_f32 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'f64':
- double ${var};
- bare_get_f64(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_f64 failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'bool':
- bool ${var};
- bare_get_bool(&ctx, &${var});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_bool failed");
- check(${var} == ${varin}, "%s", "${var} != ${varin}");
-% elif p.type == 'string':
- size_t ${varsz} = 1024;
- char *${var} = NULL;
- bare_get_str(&ctx, &${var}, &${varsz});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_str failed");
- check(${varsz} == strlen(${var}), "%lld == %lld", strlen(${var}), ${varsz});
- check(strcmp(${var}, ${varin}) == 0, "%s", "${var} != ${varin}");
- free(${var});
-% elif p.type == 'data':
- size_t ${varsz};
- uint8_t *${var} = NULL;
- bare_get_data(&ctx, &${var}, &${varsz});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_data failed");
- check(${varsz} == ${len(p.value)}, "%ln == %s", ${varsz}, "${len(p.value)}");
- bincheck(${var}, ${varin}, ${len(p.value)});
- free(${var});
-% elif p.type == 'fixed_data':
- size_t ${varsz} = ${len(p.value)};
- uint8_t *${var} = ckalloc(${varsz});
- bare_get_fixed_data(&ctx, ${var}, ${varsz});
- check(ctx.error == BARE_ERROR_NONE, "%s", "bare_get_fixed_data failed");
- bincheck(${var}, ${varin}, ${varsz});
- free(${var});
-% endif
-% endfor
-
- membuf_fini(&buf);
-}
-
-% endfor
-
-int main(int argc, char const *argv[])
-{
- (void)argc;
- (void)argv;
-
-% for name in tests.keys():
- test_${name}();
-% endfor
-
- return 0;
-}
A cbare.3.scd => cbare.3.scd +146 -0
@@ 0,0 1,146 @@
+CBARE(3)
+
+# NAME
+
+cbare - BARE encoder and decoder.
+
+# SYNOPSIS
+
+typedef enum {++
+ BARE_ERROR_NONE,++
+ BARE_ERROR_WRITE_FAILED,++
+ BARE_ERROR_READ_FAILED,++
+ BARE_ERROR_BUFFER_TOO_SMALL,++
+ BARE_ERROR_INVALID_UTF8,++
+} bare_error;
+
+typedef bare_error (\*bare_write_func)(void \*buffer, void \*src, uint64_t nbytes);++
+typedef bare_error (\*bare_read_func)(void \*buffer, void \*dst, uint64_t nbytes);
+
+struct bare_writer {++
+ void \*buffer;++
+ bare_write_func write;++
+};
+
+struct bare_reader {++
+ void \*buffer;++
+ bare_read_func read;++
+};
+
+bare_error bare_put_uint(struct bare_writer \*ctx, uint64_t x);++
+bare_error bare_get_uint(struct bare_reader \*ctx, uint64_t \*x);++
+bare_error bare_put_u8(struct bare_writer \*ctx, uint8_t x);++
+bare_error bare_get_u8(struct bare_reader \*ctx, uint8_t \*x);++
+bare_error bare_put_u16(struct bare_writer \*ctx, uint16_t x);++
+bare_error bare_get_u16(struct bare_reader \*ctx, uint16_t \*x);++
+bare_error bare_put_u32(struct bare_writer \*ctx, uint32_t x);++
+bare_error bare_get_u32(struct bare_reader \*ctx, uint32_t \*x);++
+bare_error bare_put_u64(struct bare_writer \*ctx, uint64_t x);++
+bare_error bare_get_u64(struct bare_reader \*ctx, uint64_t \*x);
+
+bare_error bare_put_int(struct bare_writer \*ctx, int64_t x);++
+bare_error bare_get_int(struct bare_reader \*ctx, int64_t \*x);++
+bare_error bare_put_i8(struct bare_writer \*ctx, int8_t x);++
+bare_error bare_get_i8(struct bare_reader \*ctx, int8_t \*x);++
+bare_error bare_put_i16(struct bare_writer \*ctx, int16_t x);++
+bare_error bare_get_i16(struct bare_reader \*ctx, int16_t \*x);++
+bare_error bare_put_i32(struct bare_writer \*ctx, int32_t x);++
+bare_error bare_get_i32(struct bare_reader \*ctx, int32_t \*x);++
+bare_error bare_put_i64(struct bare_writer \*ctx, int64_t x);++
+bare_error bare_get_i64(struct bare_reader \*ctx, int64_t \*x);
+
+bare_error bare_put_f32(struct bare_writer \*ctx, float x);++
+bare_error bare_get_f32(struct bare_reader \*ctx, float \*x);++
+bare_error bare_put_f64(struct bare_writer \*ctx, double x);++
+bare_error bare_get_f64(struct bare_reader \*ctx, double \*x);
+
+bare_error bare_put_bool(struct bare_writer \*ctx, bool x);++
+bare_error bare_get_bool(struct bare_reader \*ctx, bool \*x);
+
+bare_error bare_put_fixed_data(struct bare_writer \*ctx, uint8_t \*src, uint64_t sz);++
+bare_error bare_get_fixed_data(struct bare_reader \*ctx, uint8_t \*dst, uint64_t sz);++
+bare_error bare_put_data(struct bare_writer \*ctx, uint8_t \*src, uint64_t sz);++
+bare_error bare_get_data(struct bare_reader \*ctx, uint8_t \*dst, uint64_t sz);++
+bare_error bare_put_str(struct bare_writer \*ctx, char \*src, uint64_t sz);++
+bare_error bare_get_str(struct bare_reader \*ctx, char \*dst, uint64_t sz);
+
+# DESCRIPTION
+
+cbare is an I/O agnostic C implementation of the BARE message encoding.
+
+Each function need a pointer to either *struct bare_writer* or
+*struct bare_reader* and a value or a pointer to a value. The data and
+string functions also need a size.
+
+# EXAMPLES
+
+Serialize a uint:
+
+```
+struct bare_writer ctx = {.buffer=..., .write=...};
+bare_put_uint(&ctx, 34);
+```
+
+Deserialize a uint:
+
+```
+struct bare_reader ctx = {.buffer=..., .read=...};
+uint64_t x = 0;
+bare_get_uint(&ctx, &x);
+```
+
+Write callback for buffer:
+
+```
+struct buf {
+ uint8_t *data;
+ uint64_t cur;
+ uint64_t len;
+};
+
+static bare_error
+buf_write(void *buffer, void *src, uint64_t sz)
+{
+ struct buf *b = (struct buf *)buffer;
+
+ if (sz > (b->len-b->cur)) {
+ return BARE_ERROR_WRITE_FAILED;
+ }
+
+ memcpy(b->data + b->cur, src, sz);
+ b->cur += sz;
+
+ return BARE_ERROR_NONE;
+}
+
+struct buf b = {.data=..., .cur=0, .len=1024};
+struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+```
+
+And a read callback:
+
+```
+static bare_error
+buf_read(void *buffer, void *dst, uint64_t sz)
+{
+ struct buf *b = (struct buf *)buffer;
+
+ if (sz > (b->len-b->cur)) {
+ return BARE_ERROR_READ_FAILED;
+ }
+
+ memcpy(dst, b->data + b->cur, sz);
+ b->cur += sz;
+
+ return BARE_ERROR_NONE;
+}
+
+struct buf b = {.data=..., .cur=0, .len=1024};
+struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+```
+
+# RESOURCES
+
+- cbare: https://git.sr.ht/~fsx/cbare
+- BARE message encoding: https://baremessages.org/
+- Internet Draft: https://www.ietf.org/archive/id/draft-devault-bare-07.html
D cbare.c => cbare.c +0 -440
@@ 1,440 0,0 @@
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cbare.h"
-#include "utf8.h"
-
-#ifndef BARE_CALLOC
-#define BARE_CALLOC(num, size) calloc(num, size)
-#endif
-
-#ifndef BARE_FREE
-#define BARE_FREE(ptr) free(ptr)
-#endif
-
-#define ptr8(v) ((uint8_t *)v)
-
-enum {
- U8SZ = 1,
- U16SZ = 2,
- U32SZ = 4,
- U64SZ = 8,
- MAXVARINTSZ = 10,
-};
-
-static bool
-error_is_set(struct bare_ctx *ctx)
-{
- return ctx->error != BARE_ERROR_NONE;
-}
-
-static bool
-checkstr(const char *x, uint64_t nbytes)
-{
- if (x == NULL || nbytes == 0) {
- return true;
- }
-
- int err;
- uint32_t cp;
-
- char *buf = (void *)x;
-
- for (; (nbytes - 3) > 0; nbytes -= 4) {
- buf = utf8_decode(buf, &cp, &err);
- if (err > 0) {
- return false;
- }
- }
-
- char *pad = (char *)(char[4]){0, 0, 0, 0};
-
- if (nbytes > 0) {
- memcpy(pad, buf, nbytes);
- utf8_decode(pad, &cp, &err);
- if (err > 0) {
- return false;
- }
- }
-
- return true;
-}
-
-void
-bare_init(struct bare_ctx *ctx, void *buf, bare_reader read, bare_writer write)
-{
- memset(ctx, 0, sizeof(*ctx));
- ctx->error = BARE_ERROR_NONE;
- ctx->buf = buf;
- ctx->read = read;
- ctx->write = write;
-}
-
-void
-bare_init_reader(struct bare_ctx *ctx, void *buf, bare_reader read)
-{
- bare_init(ctx, buf, read, NULL);
-}
-
-void
-bare_init_writer(struct bare_ctx *ctx, void *buf, bare_writer write)
-{
- bare_init(ctx, buf, NULL, write);
-}
-
-void
-bare_put_uint(struct bare_ctx *ctx, uint64_t x)
-{
- uint64_t i = 0;
- uint8_t b[MAXVARINTSZ];
-
- while (x >= 0x80) {
- b[i] = (uint8_t)x | 0x80;
- x >>= 7;
- i++;
- }
-
- b[i] = (uint8_t)x;
- i++;
-
- ctx->write(ctx, b, i);
-}
-
-void
-bare_get_uint(struct bare_ctx *ctx, uint64_t *x)
-{
- uint8_t s = 0;
- uint64_t y = 0;
-
- uint64_t i = 0;
- for (i = 0;;i++) {
- uint8_t b;
- ctx->read(ctx, &b, U8SZ);
- if (error_is_set(ctx)) {
- break;
- }
-
- if (b < 0x80) {
- if (i > 9 || (i == 9 && b > 1)) {
- ctx->error = BARE_ERROR_VARUINT_OVERFLOW;
- break;
- }
-
- y |= (uint64_t)b << s;
- break;
- }
-
- y |= ((uint64_t)b & 0x7f) << s;
- s += 7;
- }
-
- *x = y;
-}
-
-void
-bare_put_u8(struct bare_ctx *ctx, uint8_t x)
-{
- ctx->write(ctx, &x, U8SZ);
-}
-
-void
-bare_get_u8(struct bare_ctx *ctx, uint8_t *x)
-{
- ctx->read(ctx, x, U8SZ);
-}
-
-void
-bare_put_u16(struct bare_ctx *ctx, uint16_t x)
-{
- ctx->write(ctx, (uint8_t[U16SZ]){x, x >> 8}, U16SZ);
-}
-
-void
-bare_get_u16(struct bare_ctx *ctx, uint16_t *x)
-{
- ctx->read(ctx, x, U16SZ);
-
- if (error_is_set(ctx)) {
- return;
- }
-
- *x = (uint16_t)ptr8(x)[0]
- | (uint16_t)ptr8(x)[1] << 8;
-}
-
-void
-bare_put_u32(struct bare_ctx *ctx, uint32_t x)
-{
- uint8_t b[U32SZ];
-
- b[0] = (uint8_t)(x);
- b[1] = (uint8_t)(x >> 8);
- b[2] = (uint8_t)(x >> 16);
- b[3] = (uint8_t)(x >> 24);
-
- ctx->write(ctx, b, U32SZ);
-}
-
-void
-bare_get_u32(struct bare_ctx *ctx, uint32_t *x)
-{
- ctx->read(ctx, x, U32SZ);
-
- if (error_is_set(ctx)) {
- return;
- }
-
- *x = (uint32_t)(ptr8(x)[0])
- | (uint32_t)(ptr8(x)[1] << 8)
- | (uint32_t)(ptr8(x)[2] << 16)
- | (uint32_t)(ptr8(x)[3] << 24);
-}
-
-void
-bare_put_u64(struct bare_ctx *ctx, uint64_t x)
-{
- uint8_t b[U64SZ];
-
- b[0] = x;
- b[1] = x >> 8;
- b[2] = x >> 16;
- b[3] = x >> 24;
- b[4] = x >> 32;
- b[5] = x >> 40;
- b[6] = x >> 48;
- b[7] = x >> 56;
-
- ctx->write(ctx, b, U64SZ);
-}
-
-void
-bare_get_u64(struct bare_ctx *ctx, uint64_t *x)
-{
- ctx->read(ctx, x, U64SZ);
-
- if (error_is_set(ctx)) {
- return;
- }
-
- *x = (uint64_t)ptr8(x)[0]
- | (uint64_t)ptr8(x)[1] << 8
- | (uint64_t)ptr8(x)[2] << 16
- | (uint64_t)ptr8(x)[3] << 24
- | (uint64_t)ptr8(x)[4] << 32
- | (uint64_t)ptr8(x)[5] << 40
- | (uint64_t)ptr8(x)[6] << 48
- | (uint64_t)ptr8(x)[7] << 56;
-}
-
-void
-bare_put_int(struct bare_ctx *ctx, int64_t x)
-{
- uint64_t ux = (uint64_t)x << 1;
-
- if (x < 0) {
- ux = ~ux;
- }
-
- bare_put_uint(ctx, ux);
-}
-
-void
-bare_get_int(struct bare_ctx *ctx, int64_t *x)
-{
- uint64_t ux;
-
- bare_get_uint(ctx, &ux);
-
- if (error_is_set(ctx)) {
- return;
- }
-
- *x = (int64_t)(ux >> 1);
-
- if ((ux & 1) != 0) {
- *x = ~(*x);
- }
-}
-
-void
-bare_put_i8(struct bare_ctx *ctx, int8_t x)
-{
- bare_put_u8(ctx, x);
-}
-
-void
-bare_get_i8(struct bare_ctx *ctx, int8_t *x)
-{
- bare_get_u8(ctx, (uint8_t *)x);
-}
-
-void
-bare_put_i16(struct bare_ctx *ctx, int16_t x)
-{
- bare_put_u16(ctx, x);
-}
-
-void
-bare_get_i16(struct bare_ctx *ctx, int16_t *x)
-{
- bare_get_u16(ctx, (uint16_t *)x);
-}
-
-void
-bare_put_i32(struct bare_ctx *ctx, int32_t x)
-{
- bare_put_u32(ctx, x);
-}
-
-void
-bare_get_i32(struct bare_ctx *ctx, int32_t *x)
-{
- bare_get_u32(ctx, (uint32_t *)x);
-}
-
-void
-bare_put_i64(struct bare_ctx *ctx, int64_t x)
-{
- bare_put_u64(ctx, x);
-}
-
-void
-bare_get_i64(struct bare_ctx *ctx, int64_t *x)
-{
- bare_get_u64(ctx, (uint64_t *)x);
-}
-
-void
-bare_put_f32(struct bare_ctx *ctx, float x)
-{
- if (isnan(x)) {
- ctx->error = BARE_ERROR_NAN;
- return;
- }
-
- uint32_t b;
- memcpy(&b, &x, U32SZ);
-
- bare_put_u32(ctx, b);
-}
-
-void
-bare_get_f32(struct bare_ctx *ctx, float *x)
-{
- ctx->read(ctx, x, U32SZ);
-}
-
-void
-bare_put_f64(struct bare_ctx *ctx, double x)
-{
- if (isnan(x)) {
- ctx->error = BARE_ERROR_NAN;
- return;
- }
-
- uint64_t b;
- memcpy(&b, &x, U64SZ);
-
- bare_put_u64(ctx, b);
-}
-
-void
-bare_get_f64(struct bare_ctx *ctx, double *x)
-{
- ctx->read(ctx, x, U64SZ);
-}
-
-void
-bare_put_bool(struct bare_ctx *ctx, bool x)
-{
- bare_put_u8(ctx, (uint8_t)x);
-}
-
-void
-bare_get_bool(struct bare_ctx *ctx, bool *x)
-{
- bare_get_u8(ctx, (uint8_t *)x);
-}
-
-uint64_t
-bare_put_fixed_data(struct bare_ctx *ctx, const uint8_t *x, uint64_t nbytes)
-{
- return ctx->write(ctx, x, nbytes);
-}
-
-uint64_t
-bare_get_fixed_data(struct bare_ctx *ctx, uint8_t *x, uint64_t nbytes)
-{
- return ctx->read(ctx, x, nbytes);
-}
-
-void
-bare_put_data(struct bare_ctx *ctx, const uint8_t *x, uint64_t nbytes)
-{
- bare_put_uint(ctx, nbytes);
-
- if (error_is_set(ctx)) {
- return;
- }
-
- bare_put_fixed_data(ctx, x, nbytes);
-}
-
-void
-bare_get_data(struct bare_ctx *ctx, uint8_t **x, uint64_t *const nbytes)
-{
- uint64_t read = 0, leftover = 0;
-
- bare_get_uint(ctx, &leftover);
-
- if (error_is_set(ctx)) {
- goto error;
- }
-
- // No need to set the last element to \0 as ckalloc zeroes all memory.
- *x = BARE_CALLOC(1, leftover + 1);
- if (*x == NULL) {
- ctx->error = BARE_ERROR_ALLOC_FAILED;
- return;
- }
-
- while (leftover > 0) {
- read += bare_get_fixed_data(ctx, (*x) + read, leftover);
- leftover -= read;
-
- if (error_is_set(ctx)) {
- goto error;
- }
- }
-
- *nbytes = read;
-
- return;
-
-error:
- if (*x != NULL) {
- BARE_FREE(*x);
- }
-}
-
-void
-bare_put_str(struct bare_ctx *ctx, const char *x, uint64_t nbytes)
-{
- if (!checkstr(x, nbytes)) {
- ctx->error = BARE_ERROR_INVALID_UTF8;
- return;
- }
-
- bare_put_data(ctx, (const uint8_t *const)x, nbytes);
-}
-
-void
-bare_get_str(struct bare_ctx *ctx, char **x, uint64_t *const nbytes)
-{
- bare_get_data(ctx, (uint8_t **)x, nbytes);
-
- if (!error_is_set(ctx) && !checkstr(*x, *nbytes)) {
- ctx->error = BARE_ERROR_INVALID_UTF8;
- }
-}
D cbare.h => cbare.h +0 -78
@@ 1,78 0,0 @@
-#ifndef BARE_H
-#define BARE_H
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-struct bare_ctx;
-
-enum bare_error {
- BARE_ERROR_NONE,
- BARE_ERROR_WRITE_FAILED,
- BARE_ERROR_READ_FAILED,
- BARE_ERROR_VARUINT_OVERFLOW,
- BARE_ERROR_NAN,
- BARE_ERROR_ALLOC_FAILED,
- BARE_ERROR_INVALID_UTF8,
-};
-
-typedef uint64_t (*bare_reader)(struct bare_ctx *ctx, void *const data, uint64_t nbytes);
-typedef uint64_t (*bare_writer)(struct bare_ctx *ctx, const void *const data, uint64_t nbytes);
-
-struct bare_ctx {
- enum bare_error error;
- void *buf;
- bare_reader read;
- bare_writer write;
- uint64_t dlen;
-};
-
-/* Initialization */
-void bare_init(struct bare_ctx *ctx, void *buf, bare_reader read, const bare_writer write);
-void bare_init_reader(struct bare_ctx *ctx, void *buf, const bare_reader read);
-void bare_init_writer(struct bare_ctx *ctx, void *buf, const bare_writer write);
-
-/* Unsigned integers */
-void bare_put_uint(struct bare_ctx *ctx, uint64_t x); /* varuint */
-void bare_get_uint(struct bare_ctx *ctx, uint64_t *const x); /* varuint */
-void bare_put_u8(struct bare_ctx *ctx, uint8_t x);
-void bare_get_u8(struct bare_ctx *ctx, uint8_t *const x);
-void bare_put_u16(struct bare_ctx *ctx, uint16_t x);
-void bare_get_u16(struct bare_ctx *ctx, uint16_t *const x);
-void bare_put_u32(struct bare_ctx *ctx, uint32_t x);
-void bare_get_u32(struct bare_ctx *ctx, uint32_t *const x);
-void bare_put_u64(struct bare_ctx *ctx, uint64_t x);
-void bare_get_u64(struct bare_ctx *ctx, uint64_t *const x);
-
-/* Signed integers */
-void bare_put_int(struct bare_ctx *ctx, int64_t x); /* varint */
-void bare_get_int(struct bare_ctx *ctx, int64_t *const x); /* varint */
-void bare_put_i8(struct bare_ctx *ctx, int8_t x);
-void bare_get_i8(struct bare_ctx *ctx, int8_t *const x);
-void bare_put_i16(struct bare_ctx *ctx, int16_t x);
-void bare_get_i16(struct bare_ctx *ctx, int16_t *const x);
-void bare_put_i32(struct bare_ctx *ctx, int32_t x);
-void bare_get_i32(struct bare_ctx *ctx, int32_t *const x);
-void bare_put_i64(struct bare_ctx *ctx, int64_t x);
-void bare_get_i64(struct bare_ctx *ctx, int64_t *const x);
-
-/* Floating point numbers */
-void bare_put_f32(struct bare_ctx *ctx, float x);
-void bare_get_f32(struct bare_ctx *ctx, float *const x);
-void bare_put_f64(struct bare_ctx *ctx, double x);
-void bare_get_f64(struct bare_ctx *ctx, double *const x);
-
-/* Booleans */
-void bare_put_bool(struct bare_ctx *ctx, bool x);
-void bare_get_bool(struct bare_ctx *ctx, bool *const x);
-
-/* UTF-8 strings and data */
-uint64_t bare_put_fixed_data(struct bare_ctx *ctx, const uint8_t *const x, uint64_t nbytes);
-uint64_t bare_get_fixed_data(struct bare_ctx *ctx, uint8_t *const x, uint64_t nbytes);
-void bare_put_data(struct bare_ctx *ctx, const uint8_t *const x, uint64_t nbytes);
-void bare_get_data(struct bare_ctx *ctx, uint8_t **x, uint64_t *const nbytes);
-void bare_put_str(struct bare_ctx *ctx, const char *const x, uint64_t nbytes);
-void bare_get_str(struct bare_ctx *ctx, char **x, uint64_t *nbytes);
-
-#endif /* BARE_H */
A cbare.pc.in => cbare.pc.in +10 -0
@@ 0,0 1,10 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+includedir=${prefix}/include
+libdir=${prefix}/lib
+
+Name: cbare
+Description: BARE encoder and decoder.
+Version: @version@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lcbare
D doanalyze.sh => doanalyze.sh +0 -11
@@ 1,11 0,0 @@
-#!/bin/sh
-
-set -e
-
-builddir="build-analyze"
-
-meson \
- --werror \
- --buildtype debug \
- "$builddir"
-ninja -C "$builddir" scan-build
D dodebug.sh => dodebug.sh +0 -13
@@ 1,13 0,0 @@
-#!/bin/sh
-
-set -e
-
-builddir="build-debug"
-
-meson \
- --werror \
- --buildtype debug \
- -Db_sanitize=address,undefined \
- "$builddir"
-meson compile -C "$builddir"
-meson test -C "$builddir"
D dorelease.sh => dorelease.sh +0 -12
@@ 1,12 0,0 @@
-#!/bin/sh
-
-set -e
-
-builddir="build-release"
-
-meson \
- --werror \
- --buildtype release \
- "$builddir"
-meson compile -C "$builddir"
-meson test -C "$builddir"
D membuf.c => membuf.c +0 -82
@@ 1,82 0,0 @@
-#include "membuf.h"
-
-#include "alloc.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-void
-membuf_init(struct membuf *buf, size_t capacity)
-{
- memset(buf, 0, sizeof(*buf));
- buf->size = 0;
- buf->cursor = 0;
- buf->capacity = capacity;
- buf->data = ckalloc(buf->capacity);
-}
-
-void
-membuf_fini(struct membuf *buf)
-{
- if (buf->data) {
- free(buf->data);
- }
-}
-
-void
-membuf_clear(struct membuf *buf)
-{
- buf->size = 0;
- buf->cursor = 0;
- memset(buf->data, 0, buf->capacity);
-}
-
-void
-membuf_grow(struct membuf *buf, size_t new_capacity)
-{
- if (new_capacity <= buf->capacity) {
- return;
- }
-
- buf->data = ckrealloc(buf->data, new_capacity);
- buf->capacity = new_capacity;
-}
-
-void
-membuf_write(struct membuf *buf, const uint8_t *data, size_t size)
-{
- if (buf->capacity < buf->size + size) {
- membuf_grow(buf, buf->size + buf->size / 2 + size);
- }
-
- memcpy(buf->data + buf->size, data, size);
- buf->size += size;
-}
-
-bool
-membuf_read(struct membuf *buf, uint8_t *dst, size_t size)
-{
- if ((buf->cursor + size) > buf->size) {
- return false;
- }
-
- memcpy(dst, buf->data + buf->cursor, size);
- buf->cursor += size;
-
- return true;
-}
-
-bool
-membuf_seek(struct membuf *buf, size_t pos)
-{
- if (pos > buf->size) {
- return false;
- }
-
- buf->cursor = pos;
-
- return true;
-}
D membuf.h => membuf.h +0 -23
@@ 1,23 0,0 @@
-#ifndef MEMBUF_H
-#define MEMBUF_H
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-struct membuf {
- uint8_t *data;
- size_t capacity;
- size_t size;
- size_t cursor; // read cursor
-};
-
-void membuf_init(struct membuf *buf, size_t capacity);
-void membuf_fini(struct membuf *buf);
-void membuf_clear(struct membuf *buf);
-void membuf_grow(struct membuf *buf, size_t new_capacity);
-void membuf_write(struct membuf *buf, const uint8_t *data, size_t size);
-bool membuf_read(struct membuf *buf, uint8_t *dst, size_t size);
-bool membuf_seek(struct membuf *buf, size_t pos);
-
-#endif /* MEMBUF_H */
D membuftest.c => membuftest.c +0 -46
@@ 1,46 0,0 @@
-#include "die.h"
-#include "membuf.h"
-
-void
-check(bool result, char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- if (!result) {
- die_va(msg, &args);
- }
- va_end(args);
-}
-
-int
-main(int argc, char const *argv[])
-{
- (void)argc;
- (void)argv;
-
- struct membuf buf;
- size_t capacity = 1024;
-
- membuf_init(&buf, capacity);
-
- check(buf.data != NULL, "data is null");
- check(buf.capacity == capacity, "%ld != %ld", buf.capacity, capacity);
- check(buf.size == 0, "%ld != %ld", buf.size, 0);
- check(buf.cursor == 0, "%ld != %ld", buf.cursor, 0);
-
- capacity = 2 * capacity;
- membuf_grow(&buf, capacity);
-
- check(buf.capacity == capacity, "%ld != %ld", buf.capacity, capacity);
- check(buf.size == 0, "%ld != %ld", buf.size, 0);
-
- uint8_t data[] = {0xFF, 0xFF, 0xFF, 0xFF};
- membuf_write(&buf, data, sizeof(data));
-
- check(buf.size == 4, "%ld != %ld", buf.size, 4);
-
- membuf_fini(&buf);
-
- return 0;
-}
D meson.build => meson.build +0 -75
@@ 1,75 0,0 @@
-project(
- 'cbare',
- 'c',
- version : '0.1',
- default_options : [
- 'c_std=c11',
- 'warning_level=3',
- ],
-)
-
-install_headers('cbare.h')
-
-sources = [
- 'cbare.c',
- 'alloc.c',
- 'die.c',
-]
-
-cbare_static = static_library('cbare', sources, install : true)
-cbare_shared = shared_library('cbare', sources, install : true)
-
-membuftest = executable(
- 'membuftest',
- 'membuftest.c',
- 'membuf.c',
- 'alloc.c',
- 'die.c',
-)
-
-pyinst = import('python').find_installation('python3')
-
-baretest_c = custom_target(
- 'baretest.c',
- output : ['baretest.c'],
- input : [
- 'scripts/genbaretests.py',
- 'baretest.c.mako',
- 'testdata/f32.txt',
- 'testdata/i16.txt',
- 'testdata/i8.txt',
- 'testdata/u16.txt',
- 'testdata/u8.txt',
- 'testdata/bool.txt',
- 'testdata/f64.txt',
- 'testdata/i32.txt',
- 'testdata/int.txt',
- 'testdata/u32.txt',
- 'testdata/uint.txt',
- 'testdata/data.txt',
- 'testdata/fixed_data.txt',
- 'testdata/i64.txt',
- 'testdata/string.txt',
- 'testdata/u64.txt',
- ],
- command : [pyinst, '@INPUT@', '@OUTPUT@'],
-)
-
-baretest = executable(
- 'baretest',
- baretest_c,
- 'alloc.c',
- 'die.c',
- 'membuf.c',
- link_with : [cbare_static],
-)
-
-utf8test = executable(
- 'utf8test',
- 'utf8test.c',
- 'die.c',
-)
-
-test('baretest', baretest)
-test('membuftest', membuftest)
-test('utf8test', utf8test)
A scripts/asan.sh => scripts/asan.sh +23 -0
@@ 0,0 1,23 @@
+#!/bin/sh
+
+set -eu
+
+# See: https://clang.llvm.org/docs/AddressSanitizer.html
+
+scriptdir="$(dirname "$(realpath "$0")")"
+. "${scriptdir}/lib.sh"
+cd "${scriptdir}/.."
+
+export ASAN_OPTIONS="detect_leaks=1"
+export CFLAGS="-fPIC \
+ -gdwarf-4 \
+ -fsanitize=address \
+ -fno-omit-frame-pointer \
+ -fno-optimize-sibling-calls \
+ -fsanitize-address-use-after-scope"
+export LDFLAGS="-fsanitize=address"
+
+buildcheck
+runtest ./baretest
+runtest ./utf8test
+doexit
D scripts/genbaretests.py => scripts/genbaretests.py +0 -205
@@ 1,205 0,0 @@
-#!/usr/bin/env python3
-
-import re
-import sys
-from pprint import pprint
-from dataclasses import dataclass
-from pathlib import Path
-
-import click
-from mako.template import Template
-from parsimonious.grammar import Grammar
-from parsimonious.nodes import NodeVisitor, Node
-from parsimonious.exceptions import ParseError
-
-
-@click.command()
-@click.argument('template', type=click.Path(exists=True, path_type=Path))
-@click.argument(
- 'test_data',
- type=click.Path(exists=True, path_type=Path),
- nargs=-1,
- required=True,
-)
-@click.argument('output', type=click.Path(exists=False, path_type=Path))
-def main(output, template, test_data):
- template = Template(filename=str(template.resolve()))
- tests = {}
-
- for fn in test_data:
- try:
- tests[fn.stem] = AttrDict(TestdataParser().parse(fn.read_text()))
- except ParseError as e:
- eprint(f"{fn}:{e.line()}:{e.column()}: {e!s}")
- sys.exit(1)
-
- output.write_text(template.render(tests=tests))
-
-
-def eprint(*args, **kwargs):
- print(*args, file=sys.stderr, **kwargs)
-
-
-class TestdataParser(NodeVisitor):
- grammar = Grammar(
- r"""
- test = ws inputs expect ws
-
- inputs = (name type value)+
- expect = "expect" sp bytes
-
- name = "name" sp ~r"[a-z_][a-z0-9_]*"i nl
- type = "type" sp type_name nl
- value = "value" sp type_value nl
-
- type_name = "uint"
- / "u8"
- / "u16"
- / "u32"
- / "u64"
- / "int"
- / "i8"
- / "i16"
- / "i32"
- / "i64"
- / "f32"
- / "f64"
- / "bool"
- / "string"
- / "data"
- / "fixed_data"
-
- type_value = bool
- / float
- / sint
- / uint
- / string
- / bytes
-
- bytes = "[" ws byte (ws+ byte)* ws "]"
- byte = ~r"0x[a-f0-9]{2}"i
- / ~r"0b[01]{1,8}"i
- / ~r"(?:[12][0-9]{2}|[1-9][0-9]|[0-9])"i
-
- sint = "-" uint
- uint = ~r"0x[a-z0-9]+"i
- / ~r"0b[01]+"i
- / ~r"\d+"
- float = ~r"\d+\.\d+"
-
- string = ~r'"(?:\\"|.)*?"'
-
- bool = "true" / "false"
-
- nl = "\n"+
- sp = (" " / "\t")+
- ws = (" " / "\t" / "\n" / "\r")*
- """
- )
-
- def generic_visit(self, node, visited_children):
- return visited_children or node
-
- def visit_test(self, node, visited_children):
- result = {}
- for child in visited_children:
- if isinstance(child, dict):
- result.update(child)
- return result
-
- def visit_inputs(self, node, visited_children):
- inputs = []
-
- for child in visited_children:
- tmp = AttrDict()
- for entry in child:
- tmp.update(entry)
- inputs.append(tmp)
-
- return {"inputs": inputs}
-
- def visit_expect(self, node, visited_children):
- return {"expect": visited_children[2]}
-
- def visit_name(self, node, visited_children):
- return {"name": node.children[2].text}
-
- def visit_type(self, node, visited_children):
- return {"type": node.children[2].text}
-
- def visit_value(self, node, visited_children):
- return {"value": visited_children[2][0]}
-
- def visit_bytes(self, node, visited_children):
- return Bytes(collect(visited_children, Byte))
-
- def visit_byte(self, node, visited_children):
- return Byte(node.text)
-
- def visit_sint(self, node, visited_children):
- return visited_children[0].text + visited_children[1]
-
- def _text_node(self, node, visited_children):
- return node.text
-
- visit_string = _text_node
- visit_uint = _text_node
- visit_float = _text_node
- visit_bool = _text_node
-
- def _ignore_node(self, node, visited_children):
- return Ignore(node)
-
- visit_nl = _ignore_node
- visit_sp = _ignore_node
- visit_ws = _ignore_node
-
-
-def collect( tree, value_type):
- xs = []
-
- def _collect(tree):
- for x in tree:
- if isinstance(x, list):
- _collect(x)
- elif isinstance(x, value_type):
- xs.append(str(x))
-
- _collect(tree)
-
- return xs
-
-
-class Bytes(list):
- pass
-
-
-class Byte(str):
- pass
-
-
-@dataclass
-class Ignore:
- node: Node
-
- def __repr__(self):
- return f"<IGNORED: {self.node.expr.name}>"
-
-
-class AttrDict(dict):
- def __getattr__(self, key):
- try:
- value = self.__getitem__(key)
- if not isinstance(value, self.__class__) \
- and isinstance(value, dict):
- self[key] = value = self.__class__(value)
- return value
- except KeyError:
- raise AttributeError(f'{key} not in {self.keys()}')
-
- def __setattr__(self, key, value):
- self.__setitem__(key, value)
-
-
-if __name__ == '__main__':
- main()
A scripts/lib.sh => scripts/lib.sh +49 -0
@@ 0,0 1,49 @@
+#!/bin/sh
+
+STATUS=0
+DEBUG=0
+CLEAN=0
+
+usage() {
+ echo "PROGRAM [-d] [-c] [-h]"
+}
+
+while getopts "dc" o; do
+ case "${o}" in
+ d)
+ DEBUG=1
+ ;;
+ c)
+ CLEAN=1
+ ;;
+ h|*)
+ usage
+ exit 0
+ esac
+done
+shift $((OPTIND-1))
+
+buildcheck() {
+ if [ "$CLEAN" = 1 ]; then
+ make clean
+ fi
+ make check
+}
+
+runtest() {
+ cmd=$1
+ if [ "$DEBUG" = "1" ]; then
+ cmd="gdb -ex run ${cmd}"
+ fi
+
+ if $cmd; then
+ echo "$1 passed"
+ else
+ echo "$1 failed"
+ STATUS=1
+ fi
+}
+
+doexit() {
+ exit $STATUS
+}
A scripts/msan.sh => scripts/msan.sh +22 -0
@@ 0,0 1,22 @@
+#!/bin/sh
+
+set -eu
+
+# See: https://clang.llvm.org/docs/MemorySanitizer.html
+
+scriptdir="$(dirname "$(realpath "$0")")"
+. "${scriptdir}/lib.sh"
+cd "${scriptdir}/.."
+
+export CC=clang
+export CFLAGS="-fPIC \
+ -gdwarf-4 \
+ -fsanitize=memory \
+ -fno-omit-frame-pointer \
+ -fno-optimize-sibling-calls"
+export LDFLAGS="-fsanitize=memory"
+
+buildcheck
+runtest ./baretest
+runtest ./utf8test
+doexit
A scripts/static-analysis.sh => scripts/static-analysis.sh +15 -0
@@ 0,0 1,15 @@
+#!/bin/sh
+
+set -eu
+
+# See: https://clang-analyzer.llvm.org/
+
+scriptdir="$(dirname "$(realpath "$0")")"
+. "${scriptdir}/lib.sh"
+cd "${scriptdir}/.."
+
+export CC=clang
+export CFLAGS="-fPIC -gdwarf-4"
+
+make clean
+scan-build make check
A scripts/ubsan.sh => scripts/ubsan.sh +19 -0
@@ 0,0 1,19 @@
+#!/bin/sh
+
+set -eu
+
+# See: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
+
+scriptdir="$(dirname "$(realpath "$0")")"
+. "${scriptdir}/lib.sh"
+cd "${scriptdir}/.."
+
+export CFLAGS="-fPIC \
+ -gdwarf-4 \
+ -fsanitize=undefined"
+export LDFLAGS="-fsanitize=undefined"
+
+buildcheck
+runtest ./baretest
+runtest ./utf8test
+doexit
R alloc.c => src/alloc.c +0 -0
R alloc.h => src/alloc.h +0 -0
A src/cbare.c => src/cbare.c +378 -0
@@ 0,0 1,378 @@
+#include <string.h>
+#include <stdbool.h>
+
+#include "cbare.h"
+#include "utf8.h"
+
+#define UNUSED(x) (void)(x)
+
+enum {
+ U8SZ = 1,
+ U16SZ = 2,
+ U32SZ = 4,
+ U64SZ = 8,
+ MAXVARINTSZ = 10,
+};
+
+static bool
+checkstr(const char *x, uint64_t sz)
+{
+ if (x == NULL || sz == 0) {
+ return true;
+ }
+
+ int err = 0;
+ uint32_t cp = 0;
+ char *buf = (void *)x;
+ uint64_t chunk = 4;
+ char *pad = (char *)(char[4]){0, 0, 0, 0};
+
+#define _utf8_decode(buf) \
+ do { \
+ buf = utf8_decode(buf, &cp, &err); \
+ if (err > 0) { \
+ return false; \
+ } \
+ } while (0)
+
+ for (; sz >= chunk; sz -= chunk) {
+ _utf8_decode(buf);
+ }
+
+ if (sz > 0) {
+ memcpy(pad, buf, sz);
+ _utf8_decode(pad);
+ }
+
+#undef _utf8_decode
+
+ return true;
+}
+
+bare_error
+bare_put_uint(struct bare_writer *ctx, uint64_t x)
+{
+ uint64_t i = 0;
+ uint8_t b[MAXVARINTSZ];
+
+ while (x >= 0x80) {
+ b[i] = (uint8_t)x | 0x80;
+ x >>= 7;
+ i++;
+ }
+
+ b[i] = (uint8_t)x;
+ i++;
+
+ return ctx->write(ctx->buffer, b, i);
+}
+
+bare_error
+bare_get_uint(struct bare_reader *ctx, uint64_t *x)
+{
+ bare_error err = BARE_ERROR_NONE;
+
+ uint8_t shift = 0;
+ uint64_t result = 0;
+
+ for (uint8_t i = 0;i < 10;i++) {
+ uint8_t b;
+
+ err = ctx->read(ctx->buffer, &b, U8SZ);
+ if (err != BARE_ERROR_NONE) {
+ break;
+ }
+
+ if (b < 0x80) {
+ result |= (uint64_t)b << shift;
+ break;
+ } else {
+ result |= ((uint64_t)b & 0x7f) << shift;
+ shift += 7;
+ }
+ }
+
+ *x = result;
+
+ return err;
+}
+
+bare_error
+bare_put_int(struct bare_writer *ctx, int64_t x)
+{
+ uint64_t ux = (uint64_t)x << 1;
+
+ if (x < 0) {
+ ux = ~ux;
+ }
+
+ return bare_put_uint(ctx, ux);
+}
+
+bare_error
+bare_get_int(struct bare_reader *ctx, int64_t *x)
+{
+ uint64_t ux;
+
+ bare_error err = bare_get_uint(ctx, &ux);
+
+ if (err == BARE_ERROR_NONE) {
+ *x = (int64_t)(ux >> 1);
+
+ if ((ux & 1) != 0) {
+ *x = ~(*x);
+ }
+ }
+
+ return err;
+}
+
+bare_error
+bare_put_u8(struct bare_writer *ctx, uint8_t x)
+{
+ return ctx->write(ctx->buffer, &x, U8SZ);
+}
+
+bare_error
+bare_get_u8(struct bare_reader *ctx, uint8_t *x)
+{
+ return ctx->read(ctx->buffer, x, U8SZ);
+}
+
+bare_error
+bare_put_u16(struct bare_writer *ctx, uint16_t x)
+{
+ return ctx->write(ctx->buffer, (uint8_t[U16SZ]){x, x >> 8}, U16SZ);
+}
+
+bare_error
+bare_get_u16(struct bare_reader *ctx, uint16_t *x)
+{
+ bare_error err = ctx->read(ctx->buffer, x, U16SZ);
+
+ if (err == BARE_ERROR_NONE) {
+ *x = (uint16_t)((uint8_t *)x)[0]
+ | (uint16_t)((uint8_t *)x)[1] << 8;
+ }
+
+ return err;
+}
+
+bare_error
+bare_put_u32(struct bare_writer *ctx, uint32_t x)
+{
+ uint8_t buf[U32SZ];
+
+ buf[0] = (uint8_t)(x);
+ buf[1] = (uint8_t)(x >> 8);
+ buf[2] = (uint8_t)(x >> 16);
+ buf[3] = (uint8_t)(x >> 24);
+
+ return ctx->write(ctx->buffer, buf, U32SZ);
+}
+
+bare_error
+bare_get_u32(struct bare_reader *ctx, uint32_t *x)
+{
+ bare_error err = ctx->read(ctx->buffer, x, U32SZ);
+
+ if (err == BARE_ERROR_NONE) {
+ *x = (uint32_t)(((uint8_t *)x)[0])
+ | (uint32_t)(((uint8_t *)x)[1] << 8)
+ | (uint32_t)(((uint8_t *)x)[2] << 16)
+ | (uint32_t)(((uint8_t *)x)[3] << 24);
+ }
+
+ return err;
+}
+
+bare_error
+bare_put_u64(struct bare_writer *ctx, uint64_t x)
+{
+ uint8_t buf[U64SZ];
+
+ buf[0] = x;
+ buf[1] = x >> 8;
+ buf[2] = x >> 16;
+ buf[3] = x >> 24;
+ buf[4] = x >> 32;
+ buf[5] = x >> 40;
+ buf[6] = x >> 48;
+ buf[7] = x >> 56;
+
+ return ctx->write(ctx->buffer, buf, U64SZ);
+}
+
+bare_error
+bare_get_u64(struct bare_reader *ctx, uint64_t *x)
+{
+ bare_error err = ctx->read(ctx->buffer, x, U64SZ);
+
+ if (err == BARE_ERROR_NONE) {
+ *x = (uint64_t)((uint8_t *)x)[0]
+ | (uint64_t)((uint8_t *)x)[1] << 8
+ | (uint64_t)((uint8_t *)x)[2] << 16
+ | (uint64_t)((uint8_t *)x)[3] << 24
+ | (uint64_t)((uint8_t *)x)[4] << 32
+ | (uint64_t)((uint8_t *)x)[5] << 40
+ | (uint64_t)((uint8_t *)x)[6] << 48
+ | (uint64_t)((uint8_t *)x)[7] << 56;
+ }
+
+ return err;
+}
+
+bare_error
+bare_put_i8(struct bare_writer *ctx, int8_t x)
+{
+ return bare_put_u8(ctx, x);
+}
+
+bare_error
+bare_get_i8(struct bare_reader *ctx, int8_t *x)
+{
+ return bare_get_u8(ctx, (uint8_t *)x);
+}
+
+bare_error
+bare_put_i16(struct bare_writer *ctx, int16_t x)
+{
+ return bare_put_u16(ctx, x);
+}
+
+bare_error
+bare_get_i16(struct bare_reader *ctx, int16_t *x)
+{
+ return bare_get_u16(ctx, (uint16_t *)x);
+}
+
+bare_error
+bare_put_i32(struct bare_writer *ctx, int32_t x)
+{
+ return bare_put_u32(ctx, x);
+}
+
+bare_error
+bare_get_i32(struct bare_reader *ctx, int32_t *x)
+{
+ return bare_get_u32(ctx, (uint32_t *)x);
+}
+
+bare_error
+bare_put_i64(struct bare_writer *ctx, int64_t x)
+{
+ return bare_put_u64(ctx, x);
+}
+
+bare_error
+bare_get_i64(struct bare_reader *ctx, int64_t *x)
+{
+ return bare_get_u64(ctx, (uint64_t *)x);
+}
+
+bare_error
+bare_put_f32(struct bare_writer *ctx, float x)
+{
+ uint32_t b;
+ memcpy(&b, &x, U32SZ);
+
+ return bare_put_u32(ctx, b);
+}
+
+bare_error
+bare_get_f32(struct bare_reader *ctx, float *x)
+{
+ return ctx->read(ctx->buffer, x, U32SZ);
+}
+
+bare_error
+bare_put_f64(struct bare_writer *ctx, double x)
+{
+ uint64_t b;
+ memcpy(&b, &x, U64SZ);
+
+ return bare_put_u64(ctx, b);
+}
+
+bare_error
+bare_get_f64(struct bare_reader *ctx, double *x)
+{
+ return ctx->read(ctx->buffer, x, U64SZ);
+}
+
+bare_error
+bare_put_bool(struct bare_writer *ctx, bool x)
+{
+ return bare_put_u8(ctx, (uint8_t)x);
+}
+
+bare_error
+bare_get_bool(struct bare_reader *ctx, bool *x)
+{
+ return bare_get_u8(ctx, (uint8_t *)x);
+}
+
+bare_error
+bare_put_fixed_data(struct bare_writer *ctx, uint8_t *src, uint64_t sz)
+{
+ return ctx->write(ctx->buffer, (void *)src, sz);
+}
+
+bare_error
+bare_get_fixed_data(struct bare_reader *ctx, uint8_t *dst, uint64_t sz)
+{
+ return ctx->read(ctx->buffer, dst, sz);
+}
+
+bare_error
+bare_put_data(struct bare_writer *ctx, uint8_t *src, uint64_t sz)
+{
+ bare_error err = BARE_ERROR_NONE;
+
+ err = bare_put_uint(ctx, sz);
+
+ if (err == BARE_ERROR_NONE) {
+ err = bare_put_fixed_data(ctx, src, sz);
+ }
+
+ return err;
+}
+
+bare_error
+bare_get_data(struct bare_reader *ctx, uint8_t *dst, uint64_t sz)
+{
+ bare_error err = BARE_ERROR_NONE;
+ uint64_t ssz = 0;
+
+ err = bare_get_uint(ctx, &ssz);
+
+ if (err == BARE_ERROR_NONE) {
+ err = ssz <= sz \
+ ? bare_get_fixed_data(ctx, dst, ssz) \
+ : BARE_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ return err;
+}
+
+bare_error
+bare_put_str(struct bare_writer *ctx, char *src, uint64_t sz)
+{
+ if (!checkstr(src, sz)) {
+ return BARE_ERROR_INVALID_UTF8;
+ }
+
+ return bare_put_data(ctx, (uint8_t *)src, sz);
+}
+
+bare_error
+bare_get_str(struct bare_reader *ctx, char *dst, uint64_t sz)
+{
+ bare_error err = bare_get_data(ctx, (uint8_t *)dst, sz);\
+
+ if (err == BARE_ERROR_NONE) {
+ err = !checkstr(dst, sz) ? BARE_ERROR_INVALID_UTF8 : err;
+ }
+
+ return err;
+}
A src/cbare.h => src/cbare.h +64 -0
@@ 0,0 1,64 @@
+#ifndef BARE_H
+#define BARE_H
+
+#include <stdint.h>
+
+typedef enum {
+ BARE_ERROR_NONE,
+ BARE_ERROR_WRITE_FAILED,
+ BARE_ERROR_READ_FAILED,
+ BARE_ERROR_BUFFER_TOO_SMALL,
+ BARE_ERROR_INVALID_UTF8,
+} bare_error;
+
+typedef bare_error (*bare_write_func)(void *buffer, void *src, uint64_t sz);
+typedef bare_error (*bare_read_func)(void *buffer, void *dst, uint64_t sz);
+
+struct bare_writer {
+ void *buffer;
+ bare_write_func write;
+};
+
+struct bare_reader {
+ void *buffer;
+ bare_read_func read;
+};
+
+bare_error bare_put_uint(struct bare_writer *ctx, uint64_t x); /* varuint */
+bare_error bare_get_uint(struct bare_reader *ctx, uint64_t *x); /* varuint */
+bare_error bare_put_u8(struct bare_writer *ctx, uint8_t x);
+bare_error bare_get_u8(struct bare_reader *ctx, uint8_t *x);
+bare_error bare_put_u16(struct bare_writer *ctx, uint16_t x);
+bare_error bare_get_u16(struct bare_reader *ctx, uint16_t *x);
+bare_error bare_put_u32(struct bare_writer *ctx, uint32_t x);
+bare_error bare_get_u32(struct bare_reader *ctx, uint32_t *x);
+bare_error bare_put_u64(struct bare_writer *ctx, uint64_t x);
+bare_error bare_get_u64(struct bare_reader *ctx, uint64_t *x);
+
+bare_error bare_put_int(struct bare_writer *ctx, int64_t x); /* varint */
+bare_error bare_get_int(struct bare_reader *ctx, int64_t *x); /* varint */
+bare_error bare_put_i8(struct bare_writer *ctx, int8_t x);
+bare_error bare_get_i8(struct bare_reader *ctx, int8_t *x);
+bare_error bare_put_i16(struct bare_writer *ctx, int16_t x);
+bare_error bare_get_i16(struct bare_reader *ctx, int16_t *x);
+bare_error bare_put_i32(struct bare_writer *ctx, int32_t x);
+bare_error bare_get_i32(struct bare_reader *ctx, int32_t *x);
+bare_error bare_put_i64(struct bare_writer *ctx, int64_t x);
+bare_error bare_get_i64(struct bare_reader *ctx, int64_t *x);
+
+bare_error bare_put_f32(struct bare_writer *ctx, float x);
+bare_error bare_get_f32(struct bare_reader *ctx, float *x);
+bare_error bare_put_f64(struct bare_writer *ctx, double x);
+bare_error bare_get_f64(struct bare_reader *ctx, double *x);
+
+bare_error bare_put_bool(struct bare_writer *ctx, bool x);
+bare_error bare_get_bool(struct bare_reader *ctx, bool *x);
+
+bare_error bare_put_fixed_data(struct bare_writer *ctx, uint8_t *src, uint64_t sz);
+bare_error bare_get_fixed_data(struct bare_reader *ctx, uint8_t *dst, uint64_t sz);
+bare_error bare_put_data(struct bare_writer *ctx, uint8_t *src, uint64_t sz);
+bare_error bare_get_data(struct bare_reader *ctx, uint8_t *dst, uint64_t sz);
+bare_error bare_put_str(struct bare_writer *ctx, char *src, uint64_t sz);
+bare_error bare_get_str(struct bare_reader *ctx, char *dst, uint64_t sz);
+
+#endif /* BARE_H */
R die.c => src/die.c +0 -0
R die.h => src/die.h +2 -2
@@ 3,7 3,7 @@
#include <stdarg.h>
-_Noreturn void die(char *msg, ...);
-_Noreturn void die_va(char *msg, va_list *args);
+void die(char *msg, ...);
+void die_va(char *msg, va_list *args);
#endif /* DIE_H */
R utf8.h => src/utf8.h +0 -0
A test/baretest.c => test/baretest.c +926 -0
@@ 0,0 1,926 @@
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <cbare.h>
+
+#include "alloc.h"
+#include "die.h"
+
+#define UNUSED(x) (void)(x)
+
+#define ARRLEN(a) sizeof(a)/sizeof(a[0])
+
+#define FOR_EACH_ARRAY(type, elem, array) \
+ for (type elem = &(array)[0]; \
+ elem < &(array)[ARRLEN(array)]; \
+ ++elem)
+
+static void
+ok(bool result, char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ if (!result) {
+ die_va(msg, &args);
+ }
+ va_end(args);
+}
+
+static void
+binok(uint8_t *a, uint8_t *b, size_t len)
+{
+ bool result = memcmp(a, b, len) == 0;
+
+ if (!result) {
+ printf("a:");
+
+ for (size_t i = 0; i < len; i++) {
+ printf(" %02x", (uint8_t) *a);
+ a++;
+ }
+
+ printf("\n");
+ printf("b:");
+
+ for (size_t i = 0; i < len; i++) {
+ printf(" %02x", (uint8_t) *b);
+ b++;
+ }
+
+ printf("\n");
+ }
+
+ ok(result, "%s", "a != b");
+}
+
+struct buf {
+ uint8_t *data;
+ uint64_t cur;
+ uint64_t len;
+};
+
+static struct buf
+buf_alloc(uint64_t sz)
+{
+ return (struct buf){.data=ckalloc(sz), .cur=0, .len=sz};
+}
+
+static struct buf
+buf_alloc_1kb()
+{
+ return buf_alloc(1024);
+}
+
+static bare_error
+buf_read(void *buffer, void *dst, uint64_t sz)
+{
+ struct buf *b = (struct buf *)buffer;
+
+ if (sz > (b->len-b->cur)) {
+ return BARE_ERROR_READ_FAILED;
+ }
+
+ memcpy(dst, b->data + b->cur, sz);
+ b->cur += sz;
+
+ return BARE_ERROR_NONE;
+}
+
+static bare_error
+buf_write(void *buffer, void *src, uint64_t sz)
+{
+ struct buf *b = (struct buf *)buffer;
+
+ if (sz > (b->len-b->cur)) {
+ return BARE_ERROR_WRITE_FAILED;
+ }
+
+ memcpy(b->data + b->cur, src, sz);
+ b->cur += sz;
+
+ return BARE_ERROR_NONE;
+}
+
+static void
+test_bare_put_uint()
+{
+ struct test {
+ uint64_t input;
+ uint8_t *output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=0, .output=(uint8_t[]){0x00}, 1},
+ {.input=1, .output=(uint8_t[]){0x01}, 1},
+ {.input=126, .output=(uint8_t[]){0x7e}, 1},
+ {.input=127, .output=(uint8_t[]){0x7f}, 1},
+ {.input=128, .output=(uint8_t[]){0x80, 0x01}, 2},
+ {.input=129, .output=(uint8_t[]){0x81, 0x01}, 2},
+ {.input=255, .output=(uint8_t[]){0xFF, 0x01}, 2},
+ {.input=5345342, .output=(uint8_t[]){0xBE, 0xA0, 0xC6, 0x02}, 4},
+ {.input=INT64_MAX, .output=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, 9},
+ {.input=UINT64_MAX, .output=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, 10},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ ok(bare_put_uint(&ctx, t->input) == BARE_ERROR_NONE, "bare_put_uint failed");
+ binok(b.data, t->output, t->len);
+ ok(b.cur == t->len, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, t->len);
+
+ free(b.data);
+ }
+}
+
+static void
+test_bare_get_uint()
+{
+ struct test {
+ uint8_t *input;
+ uint64_t output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=(uint8_t[]){0x00}, .output=0, 1},
+ {.input=(uint8_t[]){0x01}, .output=1, 1},
+ {.input=(uint8_t[]){0x7e}, .output=126, 1},
+ {.input=(uint8_t[]){0x7f}, .output=127, 1},
+ {.input=(uint8_t[]){0x80, 0x01}, .output=128, 2},
+ {.input=(uint8_t[]){0x81, 0x01}, .output=129, 2},
+ {.input=(uint8_t[]){0xFF, 0x01}, .output=255, 2},
+ {.input=(uint8_t[]){0xBE, 0xA0, 0xC6, 0x02}, .output=5345342, 4},
+ {.input=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}, .output=INT64_MAX, 9},
+ {.input=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, .output=UINT64_MAX, 10},
+ {.input=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, .output=UINT64_MAX, 11},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = {.data=t->input, .cur=0, .len=t->len};
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ uint64_t x = 0;
+ ok(bare_get_uint(&ctx, &x) == BARE_ERROR_NONE, "bare_get_uint failed");
+ ok(x == t->output, "%" PRIu64 " != %" PRIu64, x, t->output);
+ }
+}
+
+static void
+test_bare_put_int()
+{
+ struct test {
+ int64_t input;
+ uint8_t *output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=0, .output=(uint8_t[]){0x00}, 1},
+ {.input=1, .output=(uint8_t[]){0x02}, 1},
+ {.input=-1, .output=(uint8_t[]){0x01}, 1},
+ {.input=63, .output=(uint8_t[]){0x7e}, 1},
+ {.input=-63, .output=(uint8_t[]){0x7d}, 1},
+ {.input=64, .output=(uint8_t[]){0x80 , 0x1}, 2},
+ {.input=-64, .output=(uint8_t[]){0x7f}, 1},
+ {.input=65, .output=(uint8_t[]){0x82, 0x01}, 2},
+ {.input=-65, .output=(uint8_t[]){0x81, 0x01}, 2},
+ {.input=255, .output=(uint8_t[]){0xFE, 0x03}, 2},
+ {.input=-255, .output=(uint8_t[]){0xFD, 0x03}, 2},
+ {.input=INT64_MAX, .output=(uint8_t[]){0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, 10},
+ {.input=INT64_MIN, .output=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, 10},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ ok(bare_put_int(&ctx, t->input) == BARE_ERROR_NONE, "bare_put_int failed");
+ binok(b.data, t->output, t->len);
+ ok(b.cur == t->len, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, t->len);
+
+ free(b.data);
+ }
+}
+
+static void
+test_bare_get_int()
+{
+ struct test {
+ uint8_t *input;
+ int64_t output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=(uint8_t[]){0x00}, .output=0, 1},
+ {.input=(uint8_t[]){0x02}, .output=1, 1},
+ {.input=(uint8_t[]){0x01}, .output=-1, 1},
+ {.input=(uint8_t[]){0x7e}, .output=63, 1},
+ {.input=(uint8_t[]){0x7d}, .output=-63, 1},
+ {.input=(uint8_t[]){0x80 , 0x1}, .output=64, 2},
+ {.input=(uint8_t[]){0x7f}, .output=-64, 1},
+ {.input=(uint8_t[]){0x82, 0x01}, .output=65, 2},
+ {.input=(uint8_t[]){0x81, 0x01}, .output=-65, 2},
+ {.input=(uint8_t[]){0xFE, 0x03}, .output=255, 2},
+ {.input=(uint8_t[]){0xFD, 0x03}, .output=-255, 2},
+ {.input=(uint8_t[]){0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, .output=INT64_MAX, 10},
+ {.input=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, .output=INT64_MIN, 10},
+ {.input=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, .output=INT64_MIN, 10},
+ {.input=(uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, .output=INT64_MIN, 11},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = {.data=t->input, .cur=0, .len=t->len};
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ int64_t x = 0;
+ ok(bare_get_int(&ctx, &x) == BARE_ERROR_NONE, "bare_get_int failed");
+ ok(x == t->output, "%" PRIi64 " != %" PRIi64, x, t->output);
+ }
+}
+
+static void
+test_bare_put_u8()
+{
+ struct test {
+ uint64_t input;
+ uint8_t *output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=0, .output=(uint8_t[]){0x00}, 1},
+ {.input=1, .output=(uint8_t[]){0x01}, 1},
+ {.input=126, .output=(uint8_t[]){0x7e}, 1},
+ {.input=255, .output=(uint8_t[]){0xFF}, 1},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ ok(bare_put_u8(&ctx, t->input) == BARE_ERROR_NONE, "bare_put_u8 failed");
+ binok(b.data, t->output, t->len);
+ ok(b.cur == t->len, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, t->len);
+
+ free(b.data);
+ }
+
+}
+
+static void
+test_bare_get_u8()
+{
+ struct test {
+ uint8_t *input;
+ uint8_t output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=(uint8_t[]){0x00}, .output=0, 1},
+ {.input=(uint8_t[]){0x01}, .output=1, 1},
+ {.input=(uint8_t[]){0x7e}, .output=126, 1},
+ {.input=(uint8_t[]){0xFF}, .output=255, 1},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = {.data=t->input, .cur=0, .len=t->len};
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ uint8_t x = 0;
+ ok(bare_get_u8(&ctx, &x) == BARE_ERROR_NONE, "bare_get_u8 failed");
+ ok(x == t->output, "%" PRIu8 " != %" PRIu8, x, t->output);
+ }
+}
+
+static void
+test_bare_put_u32()
+{
+ struct test {
+ uint32_t input;
+ uint8_t *output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=0, .output=(uint8_t[]){0x00, 0x00, 0x00, 0x00}, 4},
+ {.input=1, .output=(uint8_t[]){0x01, 0x00, 0x00, 0x00}, 4},
+ {.input=255, .output=(uint8_t[]){0xFF, 0x00, 0x00, 0x00}, 4},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ ok(bare_put_u32(&ctx, t->input) == BARE_ERROR_NONE, "bare_put_u32 failed");
+ binok(b.data, t->output, t->len);
+ ok(b.cur == t->len, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, t->len);
+
+ free(b.data);
+ }
+}
+
+static void
+test_bare_get_u32()
+{
+ struct test {
+ uint8_t *input;
+ uint32_t output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=(uint8_t[]){0x00, 0x00, 0x00, 0x00}, .output=0, 4},
+ {.input=(uint8_t[]){0x01, 0x00, 0x00, 0x00}, .output=1, 4},
+ {.input=(uint8_t[]){0xFF, 0x00, 0x00, 0x00}, .output=255, 4},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = {.data=t->input, .cur=0, .len=t->len};
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ uint32_t x = 0;
+ ok(bare_get_u32(&ctx, &x) == BARE_ERROR_NONE, "bare_get_u32 failed");
+ ok(x == t->output, "%" PRIu32 " != %" PRIu32, x, t->output);
+ }
+}
+
+static void
+test_bare_put_i16()
+{
+ struct test {
+ int16_t input;
+ uint8_t *output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=0, .output=(uint8_t[]){0x00, 0x00}, 2},
+ {.input=1, .output=(uint8_t[]){0x01, 0x00}, 2},
+ {.input=-1, .output=(uint8_t[]){0xFF, 0xFF}, 2},
+ {.input=255, .output=(uint8_t[]){0xFF, 0x00}, 2},
+ {.input=-255, .output=(uint8_t[]){0x01, 0xFF}, 2},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ ok(bare_put_i16(&ctx, t->input) == BARE_ERROR_NONE, "bare_put_i16 failed");
+ binok(b.data, t->output, t->len);
+ ok(b.cur == t->len, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, t->len);
+
+ free(b.data);
+ }
+}
+
+static void
+test_bare_get_i16()
+{
+ struct test {
+ uint8_t *input;
+ int16_t output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=(uint8_t[]){0x00, 0x00}, .output=0, 2},
+ {.input=(uint8_t[]){0x01, 0x00}, .output=1, 2},
+ {.input=(uint8_t[]){0xFF, 0xFF}, .output=-1, 2},
+ {.input=(uint8_t[]){0xFF, 0x00}, .output=255, 2},
+ {.input=(uint8_t[]){0x01, 0xFF}, .output=-255, 2},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = {.data=t->input, .cur=0, .len=t->len};
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ int16_t x = 0;
+ ok(bare_get_i16(&ctx, &x) == BARE_ERROR_NONE, "bare_get_i16 failed");
+ ok(x == t->output, "%" PRIi16 " != %" PRIi16, x, t->output);
+ }
+}
+
+static void
+test_bare_put_f64()
+{
+
+
+ struct test {
+ double input;
+ uint8_t *output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=1.0, .output=(uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f}, 8},
+ {.input=2.55, .output=(uint8_t[]){0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x04, 0x40}, 8},
+ {.input=-25.5, .output=(uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x39, 0xC0}, 8},
+ {.input=0.0, .output=(uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ ok(bare_put_f64(&ctx, t->input) == BARE_ERROR_NONE, "bare_put_f64 failed");
+ binok(b.data, t->output, t->len);
+ ok(b.cur == t->len, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, t->len);
+
+ free(b.data);
+ }
+}
+
+static void
+test_bare_get_f64()
+{
+ struct test {
+ uint8_t *input;
+ double output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=(uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f}, .output=1.0, 8},
+ {.input=(uint8_t[]){0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x04, 0x40}, .output=2.55, 8},
+ {.input=(uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x39, 0xC0}, .output=-25.5, 8},
+ {.input=(uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, .output=0.0, 8},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = {.data=t->input, .cur=0, .len=t->len};
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ double x = 0;
+ ok(bare_get_f64(&ctx, &x) == BARE_ERROR_NONE, "bare_get_f64 failed");
+ ok(x == t->output, "%g != %g", x, t->output);
+ }
+}
+
+static void
+test_bare_put_bool()
+{
+ struct test {
+ bool input;
+ uint8_t *output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=true, .output=(uint8_t[]){0x01}, 1},
+ {.input=false, .output=(uint8_t[]){0x00}, 1},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ ok(bare_put_bool(&ctx, t->input) == BARE_ERROR_NONE, "bare_put_bool failed");
+ binok(b.data, t->output, t->len);
+ ok(b.cur == t->len, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, t->len);
+
+ free(b.data);
+ }
+}
+
+static void
+test_bare_get_bool()
+{
+ struct test {
+ uint8_t *input;
+ bool output;
+ size_t len;
+ };
+
+ struct test tests[] = {
+ {.input=(uint8_t[]){0x01}, .output=true, 1},
+ {.input=(uint8_t[]){0x00}, .output=false, 1},
+ };
+
+ FOR_EACH_ARRAY(struct test *, t, tests) {
+ struct buf b = {.data=t->input, .cur=0, .len=t->len};
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ bool x = 0;
+ ok(bare_get_bool(&ctx, &x) == BARE_ERROR_NONE, "bare_get_bool failed");
+ ok(x == t->output, "%d != %d", x, t->output);
+ }
+}
+
+static void
+test_bare_put_str()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ char *in = "BARE";
+ uint64_t inlen = strlen(in);
+
+ uint8_t out[] = {0x04, 0x42, 0x41, 0x52, 0x45};
+ uint64_t outlen = inlen + 1;
+
+ ok(bare_put_str(&ctx, in, inlen) == BARE_ERROR_NONE, "bare_put_str failed");
+ binok(b.data, out, outlen);
+ ok(b.cur == outlen, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, outlen);
+
+ free(b.data);
+}
+
+static void
+test_bare_get_str()
+{
+ char got[] = {0, 0, 0, 0};
+ char want[] = {0x42, 0x41, 0x52, 0x45};
+
+ struct buf b = {
+ .data=(uint8_t[]){0x04, 0x42, 0x41, 0x52, 0x45},
+ .cur=0,
+ .len=5,
+ };
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ ok(bare_get_str(&ctx, got, ARRLEN(got)) == BARE_ERROR_NONE, "bare_get_str failed");
+ ok(memcmp(got, want, ARRLEN(got)) == 0, "%s != %s", got, want);
+}
+
+static void
+test_bare_put_data()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ uint8_t in[] = {
+ 0xAA, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0xEE, 0xDD, 0xCC, 0xBB,
+ 0xEE, 0xDD, 0xCC, 0xBB,
+ };
+ uint64_t inlen = 16;
+
+ uint8_t out[] = {
+ 0x10, 0xAA, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0xEE, 0xDD, 0xCC,
+ 0xBB, 0xEE, 0xDD, 0xCC, 0xBB,
+ };
+ uint64_t outlen = 17;
+
+ ok(bare_put_data(&ctx, in, inlen) == BARE_ERROR_NONE, "bare_put_data failed");
+ binok(b.data, out, outlen);
+ ok(b.cur == outlen, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, outlen);
+
+ free(b.data);
+}
+
+static void
+test_bare_get_data()
+{
+ uint8_t got[16] = {0};
+ uint8_t want[16] = {
+ 0xAA, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0xEE, 0xDD, 0xCC, 0xBB,
+ 0xEE, 0xDD, 0xCC, 0xBB,
+ };
+
+ struct buf b = {
+ .data=(uint8_t[]){
+ 0x10, 0xAA, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0xEE, 0xDD,
+ 0xCC, 0xBB, 0xEE, 0xDD, 0xCC, 0xBB,
+ },
+ .cur=0,
+ .len=17,
+ };
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ ok(bare_get_data(&ctx, got, ARRLEN(got)) == BARE_ERROR_NONE, "bare_get_data failed");
+ ok(memcmp(got, want, ARRLEN(got)) == 0, "%s != %s", got, want);
+}
+
+static void
+test_bare_put_fixed_data()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ uint8_t in[] = {
+ 0xAA, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0xEE, 0xDD, 0xCC, 0xBB,
+ 0xEE, 0xDD, 0xCC, 0xBB,
+ };
+ uint64_t inlen = 16;
+
+ uint8_t out[] = {
+ 0xAA, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0xEE, 0xDD, 0xCC, 0xBB,
+ 0xEE, 0xDD, 0xCC, 0xBB,
+ };
+ uint64_t outlen = 16;
+
+ ok(bare_put_fixed_data(&ctx, in, inlen) == BARE_ERROR_NONE, "bare_put_fixed_data failed");
+ binok(b.data, out, outlen);
+ ok(b.cur == outlen, "more data than expected: %" PRIu64 " > %" PRIu64, b.cur, outlen);
+
+ free(b.data);
+}
+
+static void
+test_bare_get_fixed_data()
+{
+ uint8_t got[16] = {0};
+ uint8_t want[16] = {
+ 0xAA, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0xEE, 0xDD, 0xCC, 0xBB,
+ 0xEE, 0xDD, 0xCC, 0xBB,
+ };
+
+ struct buf b = {
+ .data=(uint8_t[]){
+ 0xAA, 0xEE, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0xEE, 0xDD, 0xCC,
+ 0xBB, 0xEE, 0xDD, 0xCC, 0xBB,
+ },
+ .cur=0,
+ .len=16,
+ };
+ struct bare_reader ctx = {.buffer=(void *)&b, .read=&buf_read};
+
+ ok(bare_get_fixed_data(&ctx, got, ARRLEN(got)) == BARE_ERROR_NONE, "bare_get_fixed_data failed");
+ ok(memcmp(got, want, ARRLEN(got)) == 0, "%s != %s", got, want);
+}
+
+// Example Values: enum {FOO BAR = 255 BUZZ}
+static void
+test_bare_enum()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 0);
+ bare_put_uint(&ctx, 255);
+ bare_put_uint(&ctx, 256);
+
+ uint8_t want[] = {0x00, 0xFF, 0x01, 0x80, 0x02};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+}
+
+// Example Values: optional<u32> = 255
+static void
+test_bare_optional_u32()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_bool(&ctx, true);
+ bare_put_u32(&ctx, 255);
+
+ uint8_t want[] = {0x01, 0xFF, 0x00, 0x00, 0x00};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+}
+
+// Example Values: list<str> = "foo" "bar" "buzz"
+static void
+test_bare_list_str()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 3);
+ bare_put_str(&ctx, "foo", 3);
+ bare_put_str(&ctx, "bar", 3);
+ bare_put_str(&ctx, "buzz", 4);
+
+ uint8_t want[] = {0x03, 0x03, 0x66, 0x6f, 0x6f, 0x03, 0x62, 0x61, 0x72, 0x04, 0x62, 0x75, 0x7A, 0x7A};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+}
+
+
+// Example Values: list<uint>[10] = 0 1 254 255 256 257 126 127 128 129
+static void
+test_bare_list_uint()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 0);
+ bare_put_uint(&ctx, 1);
+ bare_put_uint(&ctx, 254);
+ bare_put_uint(&ctx, 255);
+ bare_put_uint(&ctx, 256);
+ bare_put_uint(&ctx, 257);
+ bare_put_uint(&ctx, 126);
+ bare_put_uint(&ctx, 127);
+ bare_put_uint(&ctx, 128);
+ bare_put_uint(&ctx, 129);
+
+ uint8_t want[] = {
+ 0x00, 0x01, 0xFE, 0x01, 0xFF, 0x01, 0x80, 0x02, 0x81, 0x02, 0x7E, 0x7F,
+ 0x80, 0x01, 0x81, 0x01,
+ };
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+}
+
+// Example Values: map<u32><str> = 0 => "zero" 1 => "one" 255 => "two hundreds and fifty five"
+static void
+test_bare_map_u32_str()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 3);
+ bare_put_u32(&ctx, 0);
+ bare_put_str(&ctx, "zero", 4);
+ bare_put_u32(&ctx, 1);
+ bare_put_str(&ctx, "one", 3);
+ bare_put_u32(&ctx, 255);
+ bare_put_str(&ctx, "two hundreds and fifty five", 27);
+
+ uint8_t want[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x7A, 0x65, 0x72, 0x6F, 0x01, 0x00,
+ 0x00, 0x00, 0x03, 0x6F, 0x6E, 0x65, 0xFF, 0x00, 0x00, 0x00, 0x1B, 0x74,
+ 0x77, 0x6F, 0x20, 0x68, 0x75, 0x6E, 0x64, 0x72, 0x65, 0x64, 0x73, 0x20,
+ 0x61, 0x6E, 0x64, 0x20, 0x66, 0x69, 0x66, 0x74, 0x79, 0x20, 0x66, 0x69,
+ 0x76, 0x65,
+ };
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+}
+
+// Example Values: union {int | uint = 255 | str}
+static void
+test_bare_union()
+{
+ // 0, int
+ {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 0);
+ bare_put_int(&ctx, 0);
+
+ uint8_t want[] = {0x00, 0x00};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+ }
+
+ // 1, int
+ {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 0);
+ bare_put_int(&ctx, 1);
+
+ uint8_t want[] = {0x00, 0x02};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+ }
+
+ // 1, uint
+ {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 255);
+ bare_put_uint(&ctx, 1);
+
+ uint8_t want[] = {0xFF, 0x01, 0x01};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+ }
+
+ // -1, int
+ {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 0);
+ bare_put_int(&ctx, -1);
+
+ uint8_t want[] = {0x00, 0x01};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+ }
+
+ // 255, int
+ {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 0);
+ bare_put_int(&ctx, 255);
+
+ uint8_t want[] = {0x00, 0xFE, 0x03};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+ }
+
+ // 255, uint
+ {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 255);
+ bare_put_uint(&ctx, 255);
+
+ uint8_t want[] = {0xFF, 0x01, 0xFF, 0x01};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+ }
+
+ // -255, int
+ {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 0);
+ bare_put_int(&ctx, -255);
+
+ uint8_t want[] = {0x00, 0xFD, 0x03};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+ }
+
+ // "BARE", str
+ {
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 256);
+ bare_put_str(&ctx, "BARE", 4);
+
+ uint8_t want[] = {0x80, 0x02, 0x04, 0x42, 0x41, 0x52, 0x45};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+ }
+}
+
+// Example Values: struct {foo: uint bar: int buzz: str} = foo => 255 bar => -255 buzz => "BARE"
+static void
+test_bare_struct()
+{
+ struct buf b = buf_alloc_1kb();
+ struct bare_writer ctx = {.buffer=(void *)&b, .write=&buf_write};
+
+ bare_put_uint(&ctx, 255);
+ bare_put_int(&ctx, -255);
+ bare_put_str(&ctx, "BARE", 4);
+
+ uint8_t want[] = {0xFF, 0x01, 0xFD, 0x03, 0x04, 0x42, 0x41, 0x52, 0x45};
+ binok(b.data, want, ARRLEN(want));
+
+ free(b.data);
+}
+
+int
+main(int argc, char const *argv[])
+{
+ UNUSED(argc);
+ UNUSED(argv);
+
+ test_bare_put_uint();
+ test_bare_get_uint();
+ test_bare_put_int();
+ test_bare_get_int();
+ test_bare_put_u8();
+ test_bare_get_u8();
+ test_bare_put_u32();
+ test_bare_get_u32();
+ test_bare_put_i16();
+ test_bare_get_i16();
+ test_bare_put_f64();
+ test_bare_get_f64();
+ test_bare_put_bool();
+ test_bare_get_bool();
+ test_bare_put_str();
+ test_bare_get_str();
+ test_bare_put_data();
+ test_bare_get_data();
+ test_bare_put_fixed_data();
+ test_bare_get_fixed_data();
+ test_bare_enum();
+ test_bare_optional_u32();
+ test_bare_list_str();
+ test_bare_list_uint();
+ test_bare_map_u32_str();
+ test_bare_union();
+ test_bare_struct();
+
+ return 0;
+}
R utf8test.c => test/utf8test.c +114 -114
@@ 21,26 21,26 @@ is_surrogate(uint32_t c)
static void *
utf8_encode(void *buf, uint32_t c)
{
- uint8_t *s = buf;
- if (c >= (1L << 16)) {
- s[0] = 0xf0 | (c >> 18);
- s[1] = 0x80 | ((c >> 12) & 0x3f);
- s[2] = 0x80 | ((c >> 6) & 0x3f);
- s[3] = 0x80 | ((c >> 0) & 0x3f);
- return s + 4;
- } else if (c >= (1L << 11)) {
- s[0] = 0xe0 | (c >> 12);
- s[1] = 0x80 | ((c >> 6) & 0x3f);
- s[2] = 0x80 | ((c >> 0) & 0x3f);
- return s + 3;
- } else if (c >= (1L << 7)) {
- s[0] = 0xc0 | (c >> 6);
- s[1] = 0x80 | ((c >> 0) & 0x3f);
- return s + 2;
- } else {
- s[0] = c;
- return s + 1;
- }
+ uint8_t *s = buf;
+ if (c >= (1L << 16)) {
+ s[0] = 0xf0 | (c >> 18);
+ s[1] = 0x80 | ((c >> 12) & 0x3f);
+ s[2] = 0x80 | ((c >> 6) & 0x3f);
+ s[3] = 0x80 | ((c >> 0) & 0x3f);
+ return s + 4;
+ } else if (c >= (1L << 11)) {
+ s[0] = 0xe0 | (c >> 12);
+ s[1] = 0x80 | ((c >> 6) & 0x3f);
+ s[2] = 0x80 | ((c >> 0) & 0x3f);
+ return s + 3;
+ } else if (c >= (1L << 7)) {
+ s[0] = 0xc0 | (c >> 6);
+ s[1] = 0x80 | ((c >> 0) & 0x3f);
+ return s + 2;
+ } else {
+ s[0] = c;
+ return s + 1;
+ }
}
void
@@ 61,100 61,100 @@ main(int argc, char const *argv[])
(void)argc;
(void)argv;
- /* Make sure it can decode every character */
- {
- long failures = 0;
- for (uint32_t i = 0; i < 0x10ffff; i++) {
- if (!is_surrogate(i)) {
- int e;
- uint32_t c;
- uint8_t buf[8] = {0};
- uint8_t *end = utf8_encode(buf, i);
- uint8_t *res = utf8_decode(buf, &c, &e);
- failures += end != res || c != i || e;
- }
- }
- check(failures == 0, "decode all, errors: %ld", failures);
- }
-
- /* Reject everything outside of U+0000..U+10FFFF */
- {
- long failures = 0;
- for (uint32_t i = 0x110000; i < 0x1fffff; i++) {
- int e;
- uint32_t c;
- uint8_t buf[8] = {0};
- utf8_encode(buf, i);
- uint8_t *end = utf8_decode(buf, &c, &e);
- failures += !e;
- failures += end - buf != 4;
- }
- check(failures == 0, "out of range, errors: %ld", failures);
- }
-
-
- /* Does it reject all surrogate halves? */
- {
- long failures = 0;
- for (uint32_t i = 0xd800; i <= 0xdfff; i++) {
- int e;
- uint32_t c;
- uint8_t buf[8] = {0};
- utf8_encode(buf, i);
- utf8_decode(buf, &c, &e);
- failures += !e;
- }
- check(failures == 0, "surrogate halves, errors: %ld", failures);
- }
-
- /* How about non-canonical encodings? */
- {
- int e;
- uint32_t c;
- uint8_t *end;
-
- uint8_t buf2[8] = {0xc0, 0xA4};
- end = utf8_decode(buf2, &c, &e);
- check(e, "non-canonical len 2, 0x%02x", e);
- check(end == buf2 + 2, "non-canonical recover 2, U+%04lx",
- (uint32_t)c);
-
- uint8_t buf3[8] = {0xe0, 0x80, 0xA4};
- end = utf8_decode(buf3, &c, &e);
- check(e, "non-canonical len 3, 0x%02x", e);
- check(end == buf3 + 3, "non-canonical recover 3, U+%04lx",
- (uint32_t)c);
-
- uint8_t buf4[8] = {0xf0, 0x80, 0x80, 0xA4};
- end = utf8_decode(buf4, &c, &e);
- check(e, "non-canonical encoding len 4, 0x%02x", e);
- check(end == buf4 + 4, "non-canonical recover 4, U+%04lx",
- (uint32_t)c);
- }
-
- /* Let's try some bogus byte sequences */
- {
- int len, e;
- uint32_t c;
-
- /* Invalid first byte */
- uint8_t buf0[4] = {0xff};
- len = (uint8_t *)utf8_decode(buf0, &c, &e) - buf0;
- check(e, "bogus [ff] 0x%02x U+%04lx", e, (uint32_t)c);
- check(len == 1, "bogus [ff] recovery %d", len);
-
- /* Invalid first byte */
- uint8_t buf1[4] = {0x80};
- len = (uint8_t *)utf8_decode(buf1, &c, &e) - buf1;
- check(e, "bogus [80] 0x%02x U+%04lx", e, (uint32_t)c);
- check(len == 1, "bogus [80] recovery %d", len);
-
- /* Looks like a two-byte sequence but second byte is wrong */
- uint8_t buf2[4] = {0xc0, 0x0a};
- len = (uint8_t *)utf8_decode(buf2, &c, &e) - buf2;
- check(e, "bogus [c0 0a] 0x%02x U+%04lx", e, (uint32_t)c);
- check(len == 2, "bogus [c0 0a] recovery %d", len);
- }
+ /* Make sure it can decode every character */
+ {
+ long failures = 0;
+ for (uint32_t i = 0; i < 0x10ffff; i++) {
+ if (!is_surrogate(i)) {
+ int e;
+ uint32_t c;
+ uint8_t buf[8] = {0};
+ uint8_t *end = utf8_encode(buf, i);
+ uint8_t *res = utf8_decode(buf, &c, &e);
+ failures += end != res || c != i || e;
+ }
+ }
+ check(failures == 0, "decode all, errors: %ld", failures);
+ }
+
+ /* Reject everything outside of U+0000..U+10FFFF */
+ {
+ long failures = 0;
+ for (uint32_t i = 0x110000; i < 0x1fffff; i++) {
+ int e;
+ uint32_t c;
+ uint8_t buf[8] = {0};
+ utf8_encode(buf, i);
+ uint8_t *end = utf8_decode(buf, &c, &e);
+ failures += !e;
+ failures += end - buf != 4;
+ }
+ check(failures == 0, "out of range, errors: %ld", failures);
+ }
+
+
+ /* Does it reject all surrogate halves? */
+ {
+ long failures = 0;
+ for (uint32_t i = 0xd800; i <= 0xdfff; i++) {
+ int e;
+ uint32_t c;
+ uint8_t buf[8] = {0};
+ utf8_encode(buf, i);
+ utf8_decode(buf, &c, &e);
+ failures += !e;
+ }
+ check(failures == 0, "surrogate halves, errors: %ld", failures);
+ }
+
+ /* How about non-canonical encodings? */
+ {
+ int e;
+ uint32_t c;
+ uint8_t *end;
+
+ uint8_t buf2[8] = {0xc0, 0xA4};
+ end = utf8_decode(buf2, &c, &e);
+ check(e, "non-canonical len 2, 0x%02x", e);
+ check(end == buf2 + 2, "non-canonical recover 2, U+%04lx",
+ (uint32_t)c);
+
+ uint8_t buf3[8] = {0xe0, 0x80, 0xA4};
+ end = utf8_decode(buf3, &c, &e);
+ check(e, "non-canonical len 3, 0x%02x", e);
+ check(end == buf3 + 3, "non-canonical recover 3, U+%04lx",
+ (uint32_t)c);
+
+ uint8_t buf4[8] = {0xf0, 0x80, 0x80, 0xA4};
+ end = utf8_decode(buf4, &c, &e);
+ check(e, "non-canonical encoding len 4, 0x%02x", e);
+ check(end == buf4 + 4, "non-canonical recover 4, U+%04lx",
+ (uint32_t)c);
+ }
+
+ /* Let's try some bogus byte sequences */
+ {
+ int len, e;
+ uint32_t c;
+
+ /* Invalid first byte */
+ uint8_t buf0[4] = {0xff};
+ len = (uint8_t *)utf8_decode(buf0, &c, &e) - buf0;
+ check(e, "bogus [ff] 0x%02x U+%04lx", e, (uint32_t)c);
+ check(len == 1, "bogus [ff] recovery %d", len);
+
+ /* Invalid first byte */
+ uint8_t buf1[4] = {0x80};
+ len = (uint8_t *)utf8_decode(buf1, &c, &e) - buf1;
+ check(e, "bogus [80] 0x%02x U+%04lx", e, (uint32_t)c);
+ check(len == 1, "bogus [80] recovery %d", len);
+
+ /* Looks like a two-byte sequence but second byte is wrong */
+ uint8_t buf2[4] = {0xc0, 0x0a};
+ len = (uint8_t *)utf8_decode(buf2, &c, &e) - buf2;
+ check(e, "bogus [c0 0a] 0x%02x U+%04lx", e, (uint32_t)c);
+ check(len == 2, "bogus [c0 0a] recovery %d", len);
+ }
return 0;
}
D testdata/bool.txt => testdata/bool.txt +0 -9
@@ 1,9 0,0 @@
-name a
-type bool
-value false
-
-name b
-type bool
-value true
-
-expect [0x00 0x01]
D testdata/data.txt => testdata/data.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type data
-value [0x13 0x37 0x42]
-
-expect [0x03 0x13 0x37 0x42]
D testdata/f32.txt => testdata/f32.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type f32
-value 1337.42
-
-expect [0x71 0x2D 0xA7 0x44]
D testdata/f64.txt => testdata/f64.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type f64
-value 133713371337.42424242
-
-expect [0x9B 0x6C 0xC9 0x20 0xF0 0x21 0x3F 0x42]
D testdata/fixed_data.txt => testdata/fixed_data.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type fixed_data
-value [0x13 0x37 0x42]
-
-expect [0x13 0x37 0x42]
D testdata/i16.txt => testdata/i16.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type i16
-value -1234
-
-expect [0x2E 0xFB]
D testdata/i32.txt => testdata/i32.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type i32
-value -12345678
-
-expect [0xB2 0x9E 0x43 0xFF]
D testdata/i64.txt => testdata/i64.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type i64
-value -12345678987654321
-
-expect [0x4F 0x0B 0x6E 0x9D 0xAB 0x23 0xD4 0xFF]
D testdata/i8.txt => testdata/i8.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type i8
-value -42
-
-expect [0xD6]
D testdata/int.txt => testdata/int.txt +0 -9
@@ 1,9 0,0 @@
-name a
-type int
-value 42
-
-name b
-type int
-value -1337
-
-expect [0x54 0xf1 0x14]
D testdata/string.txt => testdata/string.txt +0 -7
@@ 1,7 0,0 @@
-name japanese
-type string
-value "こんにちは、世界!"
-
-expect [0x1B 0xE3 0x81 0x93 0xE3 0x82 0x93 0xE3 0x81 0xAB 0xE3 0x81 0xA1
- 0xE3 0x81 0xAF 0xE3 0x80 0x81 0xE4 0xB8 0x96 0xE7 0x95 0x8C 0xEF
- 0xBC 0x81]
D testdata/u16.txt => testdata/u16.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type u16
-value 0xCAFE
-
-expect [0xFE 0xCA]
D testdata/u32.txt => testdata/u32.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type u32
-value 0xDEADBEEF
-
-expect [0xEF 0xBE 0xAD 0xDE]
D testdata/u64.txt => testdata/u64.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type u64
-value 0xCAFEBABEDEADBEEF
-
-expect [0xEF 0xBE 0xAD 0xDE 0xBE 0xBA 0xFE 0xCA]
D testdata/u8.txt => testdata/u8.txt +0 -5
@@ 1,5 0,0 @@
-name a
-type u8
-value 0x42
-
-expect [0x42]
D testdata/uint.txt => testdata/uint.txt +0 -9
@@ 1,9 0,0 @@
-name a
-type uint
-value 0x7F
-
-name b
-type uint
-value 0x1337
-
-expect [0x7F 0xB7 0x26]
D todo.md => todo.md +0 -11
@@ 1,11 0,0 @@
-# TODO
-
-- [ ] Add example with static buffers.
-- [ ] Add example with membuf.
-- [ ] Look into using [theft][1].
-- [ ] Add functions for making messages, unions, etc.
-- [ ] Replace Python script for generating tests with a C program or
- Lua + lpeg.
-- [ ] Build with cproc.
-
-[1]: https://github.com/silentbicycle/theft