From 6bf6f9e37694ef54738e01907b73a5827a0b63d9 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sat, 14 May 2022 21:13:45 -0700 Subject: [PATCH] Add compress and decompress examples --- examples/compress.c | 92 ++++++++++++++++++++++++++++++++++++++ examples/decompress.c | 100 ++++++++++++++++++++++++++++++++++++++++++ examples/greenbean.c | 15 +++++-- 3 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 examples/compress.c create mode 100644 examples/decompress.c diff --git a/examples/compress.c b/examples/compress.c new file mode 100644 index 000000000..800e9532f --- /dev/null +++ b/examples/compress.c @@ -0,0 +1,92 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/assert.h" +#include "libc/errno.h" +#include "libc/log/check.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "third_party/zlib/zlib.h" + +#define CHUNK 4096 + +// clang-format off +// make -j8 o//examples && dd if=/dev/urandom count=100 | tee a | o//examples/compress.com | o//examples/decompress.com >b && sha1sum a b +// clang-format on + +int compressor(int infd, int outfd) { + z_stream zs; + int rc, flush; + unsigned have; + unsigned char *inbuf; + unsigned char *outbuf; + inbuf = gc(valloc(CHUNK)); + outbuf = gc(valloc(CHUNK)); + zs.zalloc = 0; + zs.zfree = 0; + zs.opaque = 0; + rc = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS, + DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); + if (rc != Z_OK) return rc; + do { + rc = read(infd, inbuf, CHUNK); + if (rc == -1) { + deflateEnd(&zs); + return Z_ERRNO; + } + zs.avail_in = rc; + flush = !rc ? Z_FINISH : Z_SYNC_FLUSH; + zs.next_in = inbuf; + do { + zs.avail_out = CHUNK; + zs.next_out = outbuf; + rc = deflate(&zs, flush); + assert(rc != Z_STREAM_ERROR); + have = CHUNK - zs.avail_out; + if (write(outfd, outbuf, have) != have) { + deflateEnd(&zs); + return Z_ERRNO; + } + } while (!zs.avail_out); + assert(!zs.avail_in); + } while (flush != Z_FINISH); + assert(rc == Z_STREAM_END); + deflateEnd(&zs); + return Z_OK; +} + +const char *zerr(int rc) { + switch (rc) { + case Z_ERRNO: + return strerror(errno); + case Z_STREAM_ERROR: + return "invalid compression level"; + case Z_DATA_ERROR: + return "invalid or incomplete deflate data"; + case Z_MEM_ERROR: + return "out of memory"; + case Z_VERSION_ERROR: + return "zlib version mismatch!"; + default: + unreachable; + } +} + +int main(int argc, char *argv[]) { + int rc; + rc = compressor(0, 1); + if (rc == Z_OK) { + return 0; + } else { + fprintf(stderr, "error: compressor: %s\n", zerr(rc)); + return 1; + } +} diff --git a/examples/decompress.c b/examples/decompress.c new file mode 100644 index 000000000..a8b483b6d --- /dev/null +++ b/examples/decompress.c @@ -0,0 +1,100 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/assert.h" +#include "libc/errno.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/stdio/stdio.h" +#include "third_party/zlib/zlib.h" + +#define CHUNK 4096 + +// clang-format off +// make -j8 o//examples && dd if=/dev/urandom count=100 | tee a | o//examples/compress.com | o//examples/decompress.com >b && sha1sum a b +// clang-format on + +int decompressor(int infd, int outfd) { + int rc; + unsigned have; + z_stream zs; + unsigned char *inbuf; + unsigned char *outbuf; + inbuf = gc(valloc(CHUNK)); + outbuf = gc(valloc(CHUNK)); + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; + zs.avail_in = 0; + zs.next_in = Z_NULL; + rc = inflateInit(&zs); + if (rc != Z_OK) return rc; + do { + rc = read(infd, inbuf, CHUNK); + if (rc == -1) { + inflateEnd(&zs); + return Z_ERRNO; + } + if (!rc) { + break; + } + zs.avail_in = rc; + zs.next_in = inbuf; + do { + zs.avail_out = CHUNK; + zs.next_out = outbuf; + rc = inflate(&zs, Z_SYNC_FLUSH); + assert(rc != Z_STREAM_ERROR); + switch (rc) { + case Z_NEED_DICT: + rc = Z_DATA_ERROR; + // fallthrough + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&zs); + return rc; + } + have = CHUNK - zs.avail_out; + if (write(outfd, outbuf, have) != have) { + inflateEnd(&zs); + return Z_ERRNO; + } + } while (!zs.avail_out); + } while (rc != Z_STREAM_END); + inflateEnd(&zs); + return rc == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +const char *zerr(int rc) { + switch (rc) { + case Z_ERRNO: + return strerror(errno); + case Z_STREAM_ERROR: + return "invalid compression level"; + case Z_DATA_ERROR: + return "invalid or incomplete deflate data"; + case Z_MEM_ERROR: + return "out of memory"; + case Z_VERSION_ERROR: + return "zlib version mismatch!"; + default: + unreachable; + } +} + +int main(int argc, char *argv[]) { + int rc; + rc = decompressor(0, 1); + if (rc == Z_OK) { + return 0; + } else { + fprintf(stderr, "error: decompressor: %s\n", zerr(rc)); + return 1; + } +} diff --git a/examples/greenbean.c b/examples/greenbean.c index 840926388..72b761edd 100644 --- a/examples/greenbean.c +++ b/examples/greenbean.c @@ -21,6 +21,7 @@ #include "libc/calls/struct/sigset.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timeval.h" +#include "libc/dce.h" #include "libc/fmt/itoa.h" #include "libc/intrin/kprintf.h" #include "libc/log/check.h" @@ -34,6 +35,7 @@ #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/rlimit.h" #include "libc/sysv/consts/sig.h" @@ -141,6 +143,14 @@ int Worker(void *id) { char inbuf[1500], outbuf[512], *p, *q; int clientip, client, inmsglen, outmsglen; + __atomic_load(&closingtime, &itsover, __ATOMIC_SEQ_CST); + if (itsover) break; + + if (!IsLinux() && + poll(&(struct pollfd){server, POLLIN}, 1, HEARTBEAT) < 1) { + continue; + } + // wait for client connection clientaddrsize = sizeof(clientaddr); client = accept(server, &clientaddr, &clientaddrsize); @@ -154,8 +164,6 @@ int Worker(void *id) { // side-effect that the listening socket fails with EAGAIN, every // several seconds. we can use that to our advantage to check for // the ctrl-c shutdown event; otherwise, we retry the accept call - __atomic_load(&closingtime, &itsover, __ATOMIC_SEQ_CST); - if (itsover) break; continue; } @@ -274,7 +282,8 @@ int main(int argc, char *argv[]) { __atomic_load(&workers, &haveleft, __ATOMIC_SEQ_CST); if (!haveleft) break; __builtin_ia32_pause(); - if (usleep(HEARTBEAT * 1000) == -1 && closingtime) { + usleep(HEARTBEAT * 1000); + if (closingtime) { kprintf("\rgreenbean is shutting down...\n"); } }