[
  {
    "path": "README.md",
    "content": "# tinybits\n- [x] Tiny bits and useful snippets that I keep using everywhere.\n- [x] Too simple to become libraries. Just cut & paste.\n- [x] Cross-platform C/C++.\n- [x] Public Domain.\n\n|Snippet|Language|Domain|\n|:------|:-------|:-----|\n|[tinyarc4.hpp](tinyarc4.hpp)|C++|ARC4 stream cypher|\n|[tinyassert.c](tinyassert.c)|C/C++|Old assert() macro with new tricks|\n|[tinyatoi.c](tinyatoi.c)|C|atoi() implementation|\n|[tinybenchmark.hpp](tinybenchmark.hpp)|C++|Benchmark code|\n|[tinybsearch.c](tinybsearch.c)|C|Dichotomic binary search|\n|[tinybsearch.cc](tinybsearch.cc)|C++|Dichotomic binary search|\n|[tinybuild.h](tinybuild.h)|C|Build macros|\n|[tinydebug.h](tinydebug.h)|C|Debug macros|\n|[tinydefer.cc](tinydefer.cc)|C++|Defer macro, Go style|\n|[tinydir.cc](tinydir.cc)|C++|Directory listing|\n|[tinydixy.c](tinydixy.c)|C|Small YAML-subset config file parser|\n|[tinydual.sh.bat](tinydual.sh.bat)|Bash|Dual bash/batch file|\n|[tinyendian.c](tinyendian.c)|C|Endianness conversions|\n|[tinyerror.c](tinyerror.c)|C|Error handling|\n|[tinyfsm.c](tinyfsm.c)|C|Tight FSM|\n|[tinygc.cc](tinygc.cc)|C++|Garbage collector (C++)|\n|[tinyhexbase.c](tinyhexbase.c)|C|Simple binary to ascii encoder|\n|[tinyhexdump.c](tinyhexdump.c)|C|Hexdump viewer|\n|[tinyhuman.hpp](tinyhuman.hpp)|C++|De/humanized numbers|\n|[tinyini.c](tinyini.c)|C|Config parser (ini+)|\n|[tinyjson5.c](tinyjson5.c)|C|JSON5/SJSON/JSON parser/writer|\n|[tinylog.h](tinylog.h)|C|Logging utilities|\n|[tinylogger.h](tinylogger.h)|C|Simplest colorful logger|\n|[tinylogger.hpp](tinylogger.hpp)|C++|Session logger|\n|[tinymatch.c](tinymatch.c)|C|Wildcard/pattern matching|\n|[tinymime.c](tinymime.c)|C|MIME/file-type detection|\n|[tinypipe.hpp](tinypipe.hpp)|C++11|Chainable pipes|\n|[tinyprint.cc](tinyprint.cc)|C++|Comma-based printer|\n|[tinypulse.c](tinypulse.c)|C|Digital pulses|\n|[tinyroman.cc](tinyroman.cc)|C++|Integer to roman literals|\n|[tinystring.c](tinystring.c)|C|C string library|\n|[tinystring.cc](tinystring.cc)|C++|C++ string utilities|\n|[tinytga.c](tinytga.c)|C|TGA writer (fork)|\n|[tinytime.cc](tinytime.cc)|C++|Timing utilities|\n|[tinytodo.c](tinytodo.c)|C|TODO() macro|\n|[tinytty.c](tinytty.c)|C|Terminal utilities|\n|[tinyunit.c](tinyunit.c)|C|Unit-testing|\n|[tinyuniso.cc](tinyuniso.cc)|C++|.iso/9960 unarchiver|\n|[tinyuntar.cc](tinyuntar.cc)|C++|.tar unarchiver|\n|[tinyunzip.cc](tinyunzip.cc)|C++|.zip unarchiver|\n|[tinyvariant.cc](tinyvariant.cc)|C++|Variant class|\n|[tinyvbyte.h](tinyvbyte.h)|C|vbyte encoder/decoder (VLE)|\n|[tinywav.c](tinywav.c)|C|WAV writer (fork)|\n|[tinywtf.h](tinywtf.h)|C/C++|Portable host macros|\n|[tinyzlib.cpp](tinyzlib.cpp)|C++|zlib inflater|\n"
  },
  {
    "path": "UNLICENSE.md",
    "content": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <http://unlicense.org>\n"
  },
  {
    "path": "tinyarc4.hpp",
    "content": "// tinyARC4, ARC4 stream cypher. based on code by Mike Shaffer.\n// - rlyeh, public domain ~~ listening to Black Belt - Leeds | wtrmrkrlyeh\n\n#pragma once\n#include <string>\n\nstatic\nstd::string tinyARC4( const std::string &text, const std::string &passkey ) {\n    int sbox[256], key[256];\n    std::string output;\n    size_t plen = passkey.size(), tlen = text.size();\n    if( plen ) {\n        output.resize( text.size() );\n        for( size_t a = 0; a < 256; a++ ) {\n            key[ a ] = passkey[ a % plen ];\n            sbox[ a ] = a;\n        }\n        for( size_t a = 0, b = 0; a < 256; a++ ) {\n            b = (b + sbox[ a ] + key[ a ]) % 256;\n            int swap = sbox[ a ]; sbox[ a ] = sbox[ b ]; sbox[ b ] = swap;\n        }\n        for( size_t a = 0, i = 0, j = 0, k; a < tlen; a++ ) {\n            i = (i + 1) % 256;\n            j = (j + sbox[ i ]) % 256;\n            int swap = sbox[ i ]; sbox[ i ] = sbox[ j ]; sbox[ j ] = swap;\n            k = sbox[(sbox[ i ] + sbox[j]) % 256];\n            output[ a ] = text[ a ] ^ k;\n        }\n    } else output = text;\n    return output;\n}\n\n/*\n#include <cassert>\n#include <iostream>\nint main( int argc, const char **argv ) {\n    // sample\n    std::string encrypted = tinyARC4( \"Hello world.\", \"my-password\" );\n    std::string decrypted = tinyARC4( encrypted, \"my-password\" );\n\n    std::cout << \"ARC4 Encrypted text: \" << encrypted << std::endl;\n    std::cout << \"ARC4 Decrypted text: \" << decrypted << std::endl;\n\n    // tests\n    assert( tinyARC4(\"hello world\", \"my key\") != \"hello world\" );\n    assert( tinyARC4(tinyARC4(\"hello world\", \"my key\"), \"my key\") == \"hello world\" );\n}\n*/\n"
  },
  {
    "path": "tinyassert.c",
    "content": "// old assert() macro with new tricks.\n// - rlyeh, public domain.\n//\n// - [x] log failures always. break debugger only once per failure.\n// - [x] enabled always. even in optimized builds. unless ASSERT_LEVEL is 0.\n// - [x] allow messages. ie, assert(my_var != 5, \"failed my_var!=%d\", my_var).\n// - [x] break debugger only if present (hassle developers; dont hassle users).\n// - [x] overridable logger & debugger break. tip: may define ASSERT_BREAK as abort(), or leave it blank as well.\n// - [x] filter out by configurable range (to speed up things when having thousand of expensive asserts). see ASSERT_LEVEL.\n\n// configuration: percentage of random checked asserts: [0%(none)..50%(half)..100%(all)]. default: 100%\n#ifndef ASSERT_LEVEL\n#define ASSERT_LEVEL 100 \n#endif\n\n// impl below ------------------------------------------------------------------\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <assert.h>\n#undef assert\n\n// default logger: dump to stderr\n#ifndef ASSERT_LOG\n#define ASSERT_LOG(x) do { fprintf(stderr, \"%s\\n\", (x)); } while(0)\n#endif\n\n// default break behavior: break if debugged.\n#  if !defined ASSERT_BREAK && defined _WIN32\n#define ASSERT_BREAK() do{ if(IsDebuggerPresent()) __debugbreak(); } while(0)\n#include <winsock2.h> // needed for __cplusplus\n#elif !defined ASSERT_BREAK // && defined __unix__\n#define ASSERT_BREAK() do { signal(SIGTRAP, break_handler_); raise(SIGTRAP); } while(0)\n#include <signal.h>\nstatic void break_handler_(int signum) { signal(SIGTRAP, SIG_DFL); }\n#endif\n\n#if (ASSERT_LEVEL <= 0) || defined SHIPPING\n#define assert(EXPR, ...) (void)0\n#else\n#define assert(EXPR, ...) do { \\\n    static int64_t maybe = -1; if(maybe < 0) { \\\n            /* original splitmix64 by Sebastiano Vigna (CC0)*/ \\\n            uint64_t z = (__LINE__ + __COUNTER__ + UINT64_C(0x9E3779B97F4A7C15)); \\\n            z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); \\\n            maybe = (unsigned)((z ^ (z >> 31)) % 100) < ASSERT_LEVEL; } \\\n        if( maybe ) { \\\n            int msvc_trick[] = {0,}; \\\n            if( !(EXPR) ) { \\\n                char text[4096], *ptr = text; \\\n                ptr += sprintf( ptr, \"!\" __VA_ARGS__ ); \\\n                ptr += text[1] ? 0 : sprintf( ptr, \"Assertion failed: %s\", #EXPR ); \\\n                ptr += sprintf( ptr, \" (unexpected) %s:%d\", __FILE__, __LINE__); \\\n                ASSERT_LOG((1+text)); \\\n                msvc_trick[0]++; /* fool clang -Wunused-variable */ \\\n                static int once = 1; for(;once;once=0) ASSERT_BREAK(); \\\n            } \\\n        } \\\n    } while(0)\n#endif\n\n#if 0 // demo\nint main() {\n    for( int i = 0; i < 3; ++i ) {\n        assert(i < 2);\n        assert(i < 2, \"Error! %d should be smaller than %d\", i, 2);\n    }\n    puts(\"Program continues over here unless debugger is attached...\");\n}\n#endif\n"
  },
  {
    "path": "tinyatoi.c",
    "content": "// Tiny atoi() replacement. rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n\nstatic\nint tinyatoi( const char *s ) {\n    int v = 0, n = 1;\n    if( s ) {\n        while( *s == '-' ) n *= -1, s++;\n        while( *s >= '0' && *s <= '9') v = (v * 10) + *s++ - '0';\n    }\n    return n * v;\n}\n\n/*\n#include <assert.h>\nint main() {\n    assert( 1230 == tinyatoi(\"01230\") );\n    assert( -1230 == tinyatoi(\"-01230\") );\n    assert( 1230 == tinyatoi(\"--01230\") );\n    assert( -1230 == tinyatoi(\"---01230\") );\n}\n*/\n"
  },
  {
    "path": "tinybenchmark.hpp",
    "content": "// tiny benchmarks. OpenMP required.\n// - rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <omp.h>\n#include <stdio.h>\nstruct bench {\n    double line, time;\n    operator bool() const { return true; }\n    ~bench() { printf(\"L%d %gms\\n\", (int)line, (omp_get_wtime() - time) * 1000); }\n};\n#define bench if( const bench x = { __LINE__, omp_get_wtime() } ) \n\n/*\nint main() {\n   bench {\n        for( int i = 0; i < 100000000; ++i );\n        puts(\"hello stdio\");\n   }\n}\n*/\n"
  },
  {
    "path": "tinybsearch.c",
    "content": "// Tiny binary search (dichotomic): array must be sorted && supporting sequential access.\n// - rlyeh, public domain | wtrmrkrlyeh\n\n#include <string.h>\n\nunsigned bsearchint( const int *array, int numelems, int key ) {\n    int min = 0, max = numelems;\n    while( min <= max ) {\n        int mid = min + ( max - min ) / 2;\n        /**/ if( key == array[mid] ) return mid;\n        else if( key <  array[mid] ) max = mid - 1;\n        else min = mid + 1;\n    }\n    return ~0u;\n}\nunsigned bsearchsz( const size_t *array, int numelems, size_t key ) {\n    int min = 0, max = numelems;\n    while( min <= max ) {\n        int mid = min + ( max - min ) / 2;\n        /**/ if( key == array[mid] ) return mid;\n        else if( key <  array[mid] ) max = mid - 1;\n        else min = mid + 1;\n    }\n    return ~0u;\n}\nunsigned bsearchstr( const char **array, int numelems, const char *key ) {\n    int min = 0, max = numelems;\n    while( min <= max ) {\n        int mid = min + ( max - min ) / 2;\n        int search = strcmp(key, array[mid]);\n        /**/ if( 0 ==search ) return mid;\n        else if( search < 0 ) max = mid - 1;\n        else min = mid + 1;\n    }\n    return ~0u;\n}\n\n/*\n#include <assert.h>\nint main() {\n                      // @ [0]    [1]            [2]        [3]\n    const char *dict[] = { \"abc\", \"abracadabra\", \"ale hop\", \"all your base\"};\n\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"abc\") == 0 );           // @ [0]\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"abracadabra\") == 1 );   // @ [1]\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"ale hop\") ==   2 );     // @ [2]\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"all your base\") == 3 ); // @ [3]\n\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"are belong to us\") == ~0u ); // not found\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"move\") == ~0u ); // not found\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"every\") == ~0u ); // not found\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"zig\") == ~0u ); // not found\n    assert( bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), \"\") == ~0u ); // not found\n\n    for( int i = 0; i < sizeof(dict) / sizeof(dict[0]); ++i ) {\n        assert( i == bsearchstr(dict, sizeof(dict) / sizeof(dict[0]), dict[i]) );\n    }\n}\n*/\n"
  },
  {
    "path": "tinybsearch.cc",
    "content": "// Tiny binary search (dichotomic): container must be sorted && supporting sequential access.\n// - rlyeh, public domain | wtrmrkrlyeh\n\ntemplate<typename container, typename T>\nunsigned bsearch( const T &x, const container &v ) {\n    int min = 0, max = int(v.size());\n    while( min <= max ) {\n        int mid = min + ( max - min ) / 2;\n        /**/ if( x == v[mid] ) return mid;\n        else if( x  < v[mid] ) max = mid - 1;\n        else min = mid + 1;\n    }\n    return ~0u;\n}\n\n/*\n#include <cassert>\n#include <vector>\nint main() {\n                    // @ [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]\n    std::vector<int> v {  0,  1,  2,  3,  5,  6,  7, 10, 11, 12,  13,  15,  16 };\n\n    assert( bsearch( 0, v) ==   0 ); // @ [ 0]\n    assert( bsearch(10, v) ==   7 ); // @ [ 7]\n    assert( bsearch(11, v) ==   8 ); // @ [ 8]\n    assert( bsearch(15, v) ==  11 ); // @ [11]\n    assert( bsearch(16, v) ==  12 ); // @ [12]\n    assert( bsearch(-3, v) == ~0u ); // not found\n    assert( bsearch(18, v) == ~0u ); // not found\n    assert( bsearch( 8, v) == ~0u ); // not found\n    assert( bsearch( 9, v) == ~0u ); // not found\n\n    for( const auto &i : v ) {\n        assert( v[bsearch(i,v)] == i );\n    }\n}\n*/\n"
  },
  {
    "path": "tinybuild.h",
    "content": "// Tiny buildinfo macros\n// - rlyeh, public domain | wtrmrkrlyeh\n\n#pragma once\n\n#ifndef BUILD_GIT_BRANCH\n#define BUILD_GIT_BRANCH   \"n/a\"\n#endif\n\n#ifndef BUILD_GIT_REVISION\n#define BUILD_GIT_REVISION \"NaN\"\n#endif\n\n#ifndef BUILD_BITS\n#if _WIN64 || __x86_64__ || __ppc64__\n#define BUILD_BITS 64\n#elif _WIN32 || __GNUC__\n#define BUILD_BITS 32\n#else\n#define BUILD_BITS 00\n#endif\n#endif\n\n#ifndef BUILD_PROJECT\n#define BUILD_PROJECT \"UNNAMED\"\n#endif\n\n#ifndef BUILD_VERSION\n#define BUILD_VERSION \"0.0.0\"\n#endif\n\n#ifndef BUILD_URL\n#define BUILD_URL     \"https://\"\n#endif\n\n#ifndef BUILD_STAMP\n#define BUILD_STAMP   __DATE__ \" \" __TIME__\n#endif\n\n#ifndef BUILD_STR\n#define BUILD_S7R(a)  #a\n#define BUILD_STR(a)  BUILD_S7R(a)\n#endif\n\n#ifndef BUILD_ARCH\n#define BUILD_ARCH    BUILD_STR(BUILD_BITS) \"-bit\"\n#endif\n\n#ifndef BUILD_TYPE\n#define BUILD_TYPE    \"DEBUG\"\n#endif\n\n#ifndef BUILD_INFO\n#define BUILD_INFO    BUILD_PROJECT \" \" BUILD_VERSION \" (\" BUILD_ARCH \" \" BUILD_TYPE \") (\" BUILD_STAMP \") (git:\" BUILD_GIT_BRANCH \" rev:\" BUILD_GIT_REVISION \")\"\n#endif\n\n/*\n#include <stdio.h>\nint main() {\n    puts( BUILD_INFO );\n}\n*/\n"
  },
  {
    "path": "tinydebug.h",
    "content": "// Tiny debug macros\n// - rlyeh, public domain | wtrmrkrlyeh\n//\n// Build cube of 3 dimensions, 5 levels each:\n//\n//     . PUBLIC AXIS: 0 STUDIO/INTERNAL, 1 QA, 2 USER-TESTING, 3 SHOWCASE, 4 SHIPPING/MASTER\n//    /\n//   /\n//  +--------> DEBUG AXIS: 0 FATAL, 1 ERROR, 2 WARN, 3 INFO, 4 VERBOSE\n//  |\n//  |\n//  |\n//  V OPTIMIZATION AXIS: 0 DEBUG, 1 DEBUGOPT, 2 OPTSYM, 3 OPTMAX, 4 STRIPPED\n//\n// Example: a RETAIL build might be PUB>=3 DBG<=1 OPT>=3\n\n#pragma once\n\n#if defined(DEBUG) && (defined(NDEBUG) || defined(_NDEBUG))\n#undef DEBUG      // NDEBUG has precedence\n#endif\n\n#ifndef DBGLVL\n#define DBGLVL (0)\n#endif\n\n#ifndef OPTLVL\n#define OPTLVL (0)\n#endif\n\n#ifndef PUBLVL\n#define PUBLVL (0)\n#endif\n\n#if DBGLVL\n#define REL  if(0)\n#define DBG  if(1)\n#define DBG0 if(DBGLVL >= 0)\n#define DBG1 if(DBGLVL >= 1)\n#define DBG2 if(DBGLVL >= 2)\n#define DBG3 if(DBGLVL >= 3)\n#define DBG4 if(DBGLVL >= 4)\n#else\n#define REL  if(1)\n#define DBG  if(0)\n#define DBG0 if(0)\n#define DBG1 if(0)\n#define DBG2 if(0)\n#define DBG3 if(0)\n#define DBG4 if(0)\n#endif\n\n#if OPTLVL\n#define OPT  if(1)\n#define OPT0 if(OPTLVL == 0)\n#define OPT1 if(OPTLVL >= 1)\n#define OPT2 if(OPTLVL >= 2)\n#define OPT3 if(OPTLVL >= 3)\n#define OPT4 if(OPTLVL >= 4)\n#else\n#define OPT  if(0)\n#define OPT0 if(1)\n#define OPT1 if(0)\n#define OPT2 if(0)\n#define OPT3 if(0)\n#define OPT4 if(0)\n#endif\n\n#if PUBLVL\n#define DEV  if(0)\n#define PUB  if(1)\n#define PUB0 if(PUBLVL >= 0)\n#define PUB1 if(PUBLVL >= 1)\n#define PUB2 if(PUBLVL >= 2)\n#define PUB3 if(PUBLVL >= 3)\n#define PUB4 if(PUBLVL >= 4)\n#else\n#define DEV  if(1)\n#define PUB  if(0)\n#define PUB0 if(0)\n#define PUB1 if(0)\n#define PUB2 if(0)\n#define PUB3 if(0)\n#define PUB4 if(0)\n#endif\n\n// aliases\n#define DEBUGSYM DEV DBG OPT0\n#define DEBUGOPT DEV DBG OPT2\n#define DEVELSYM DEV REL OPT0\n#define DEVELOPT DEV REL OPT2\n#define SHIPPING PUB REL OPT3\n\n/*\n#include <stdio.h>\n#include <string.h>\nint main() {\n    DBG      puts(\"shown in debug builds\");\n    REL      puts(\"shown in release builds\");\n    DEV      puts(\"shown in internal development builds\");\n    DEV OPT0 puts(\"shown in internal development builds, with no optimization level\");\n    PUB OPT3 puts(\"shown in public builds with optimization level >= 3\");\n    SHIPPING puts(\"shown in final builds\");\n\n    char collected_flags[128] = {0};\n    char *buf = collected_flags;\n\n    DBG  strcat(buf, \"DEBUG,\");\n    REL  strcat(buf, \"RELEASE,\");\n\n    DBG0 strcat(buf, \"DEBUG >= 0,\");\n    DBG1 strcat(buf, \"DEBUG >= 1,\");\n    DBG2 strcat(buf, \"DEBUG >= 2,\");\n    DBG3 strcat(buf, \"DEBUG >= 3,\");\n    DBG4 strcat(buf, \"DEBUG >= 4,\");\n\n    OPT0 strcat(buf, \"OPTIM == 0,\");\n    OPT1 strcat(buf, \"OPTIM == 1,\");\n    OPT2 strcat(buf, \"OPTIM == 2,\");\n    OPT3 strcat(buf, \"OPTIM == 3,\");\n    OPT4 strcat(buf, \"OPTIM == 4,\");\n\n    OPT0 DBG strcat(buf, \"DEVELDBG (OPT0 && DBG && DEV),\");\n    OPT2 DBG strcat(buf, \"DEVELOPT (OPT2 && DBG && DEV),\");\n    OPT2 REL strcat(buf, \"OPTIMSYM (OPT2 && REL && DEV),\");\n    SHIPPING strcat(buf, \"SHIPPING (OPT3 && REL && PUB),\");\n\n    puts( collected_flags );\n}\n*/\n"
  },
  {
    "path": "tinydefer.cc",
    "content": "// tinydefer, Go style\n// - rlyeh, public domain.\n\n#include <functional>\n\nstruct defer {\n    std::function<void()> fn;\n    ~defer() { fn(); }\n};\n\n#define DEFER_MERGE_(a,b)  a##b\n#define DEFER_LABEL_(a)    DEFER_MERGE_(unique_name_, a)\n#define DEFER_UNIQUE_NAME  DEFER_LABEL_(__LINE__)\n#define defer        defer DEFER_UNIQUE_NAME; DEFER_UNIQUE_NAME.fn = [&]\n\n/*\n#include <stdio.h>\nint main() {\n    puts(\"1\");\n\n    defer {\n        puts(\"2\");\n        puts(\"3\");\n    };\n\n    defer {\n        puts(\"4\");\n        puts(\"5\");\n    };\n\n    puts(\"6\");\n}\n*/\n"
  },
  {
    "path": "tinydir.cc",
    "content": "// tiny directory listing\n// - rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <string>\n\n#ifdef _WIN32\n#include <winsock2.h>\n#else\n#include <dirent.h>\n#endif\n\ntemplate<typename FN>\nbool tinydir( const char *directory, const FN &yield ) {\n    std::string src( directory );\n    while( !src.empty() && (src.back() == '/' || src.back() == '\\\\') ) src.pop_back();\n#ifdef _WIN32\n    WIN32_FIND_DATA fdata;\n    for( HANDLE h = FindFirstFileA( (src + \"/*\").c_str(), &fdata ); h != INVALID_HANDLE_VALUE; ) {\n        for( bool next = true; next; next = FindNextFileA( h, &fdata ) != 0 ) {\n            if( fdata.cFileName[0] != '.' ) {\n                yield( (src + \"/\" + fdata.cFileName).c_str(), (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0 );\n            }\n        }\n        return FindClose( h ), true;\n    }\n#else\n    for( DIR *dir = opendir( (src + \"/\").c_str() ); dir; ) {\n        for( struct dirent *ep; ep = readdir( dir ); ) {\n            if( ep->d_name[0] != '.' ) {\n                DIR *tmp = opendir( ep->d_name );\n                yield( (src + \"/\" + ep->d_name).c_str(), tmp ? (closedir( tmp ), 1) : 0 );\n            }\n        }\n        return closedir( dir ), true;\n    }\n#endif\n    return false;\n}\n\n/*\n#include <stdio.h>\n#include <functional>\nint main() {\n    std::function<void(const char *,bool)> callback = [&]( const char *name, bool is_dir ) {\n        printf( \"%5s %s\\n\", is_dir ? \"<dir>\" : \"\", name );\n        //if( is_dir ) tinydir( name, callback ); // <-- uncomment for recursive listing\n    };\n    return tinydir( \"./\", callback );\n}\n*/\n"
  },
  {
    "path": "tinydixy.c",
    "content": "// tinydixy, small hierarchical config file format (subset of YAML, spec in https://github.com/kuyawa/Dixy)\n// - rlyeh, public domain\n\n// api, returns number of pairs found\n\nint tinydixy( const char *buffer, int (*yield)(const char *key, const char *val) );\n\n// implementation\n\n#include <stdio.h>\n#include <stdlib.h>\n\nint tinydixy( const char *s, int (*yield)(const char *key, const char *val) ) {\n    char *map = 0;\n    int mapcap = 0, maplen = 0, num_pairs_found = 0;\n    enum { DEL, REM, KEY, SUB, VAL } fsm = DEL;\n    const char *cut[5] = {0}, *end[5] = {0};\n    while( *s ) {\n        while( *s && (*s == '\\r' || *s == '\\n') ) ++s;\n        /**/ if( *s == '#' ) cut[fsm = REM] = ++s;\n        else if( *s == ' ' || *s == '\\t' ) cut[fsm = SUB] = ++s;\n        else if( *s == ':' ) cut[fsm = VAL] = ++s;\n        else if( *s > ' ' && *s <= 'z' ) cut[fsm = KEY] = cut[SUB] = end[SUB] = s, free(map), map = 0, mapcap = 0, maplen = 0;\n        else { ++s; continue; }\n        /**/ if( fsm == REM ) { while(*s && *s != '\\r'&& *s != '\\n') ++s; }\n        else if( fsm == KEY ) { while(*s && *s >  ' ' && *s <= 'z' && *s != ':') ++s; end[fsm] = s; }\n        else if( fsm == SUB ) { while(*s && *s >  ' ' && *s <= 'z' && *s != ':') ++s; end[fsm] = s; }\n        else if( fsm == VAL ) { while(*s && *s >= ' ' && *s <= 'z' && *s != '\\r' && *s != '\\n') ++s; end[fsm] = s;\n            while( end[fsm][-1] == ' ' ) --end[fsm];\n            char buf[256] = {0}, *key = buf, *val = \"\";\n            if( end[KEY] - cut[KEY] ) key += sprintf(key,  \"%.*s\", end[KEY] - cut[KEY], cut[KEY] );\n            if( end[SUB] - cut[SUB] ) key += sprintf(key, \".%.*s\", end[SUB] - cut[SUB], cut[SUB] );\n            int reqlen = (key - buf) + 1 + (end[VAL] - cut[VAL]) + 1 + 1;\n            if( (reqlen + maplen) >= mapcap ) map = realloc( map, mapcap += reqlen + 512 );\n            sprintf( map + maplen, \"%.*s%c%.*s%c%c\", key - buf, buf, 0, end[VAL] - cut[VAL], cut[VAL], 0, 0 );\n            val = map + maplen + (key - buf) + 2, key = map + maplen;\n            if( val[0] ) { yield( key, val ); num_pairs_found++; }\n            maplen += reqlen - 1;\n        }\n    }\n    free( map );\n    return num_pairs_found;\n}\n\n// sample\n/*\nint puts2( const char *key, const char *val ) {\n    printf(\"%s:'%s'\\n\", key, val);\n    return 0;\n}\n\nint main() {\n    const char *sample = \n    \"# Dixy 1.0\\n\"\n    \"\\n\"\n    \"name: Taylor Swift\\n\"\n    \"age: 27\\n\"\n    \"phones:\\n\"\n    \"    0: 555-SWIFT\\n\"\n    \"    1: 900-SWIFT\\n\"\n    \"    2: 800-TAYLOR\\n\"\n    \"body:\\n\"\n    \"    height: 6 ft\\n\"\n    \"    weight: 120 lbs\\n\"\n    \"pets:\\n\"\n    \"    0:\\n\"\n    \"        name: Fido\\n\"\n    \"        breed: chihuahua\\n\"\n    \"    1:\\n\"\n    \"        name: Tinkerbell\\n\"\n    \"        breed: bulldog\\n\";\n\n    printf(\"%d keys found\\n\", tinydixy( sample, puts2 ));\n}\n*/\n"
  },
  {
    "path": "tinydual.sh.bat",
    "content": "#/bin/bash 2>nul || goto :windows\n\n# bash\necho hello Bash\nls\nexit\n\n:windows\n@echo off\necho hello Windows\nver\nexit /b\n"
  },
  {
    "path": "tinyendian.c",
    "content": "// Tiny endianness. rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <stdint.h>\n\n#define IS_BIG_ENDIAN (*(uint16_t *)\"\\0\\1\" == 1)\nstatic uint16_t swap16( uint16_t x ) { return (x << 8) | (x >> 8); }\nstatic uint32_t swap32( uint32_t x ) { return (x << 24) | (x >> 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00); }\nstatic uint64_t swap64( uint64_t x ) { return (x << 56) | (x >> 56) | ((x & 0xff00) << 40) | ((x >> 40) & 0xff00) | ((x & 0xff0000) << 24) | ((x >> 24) & 0xff0000) | ((x & 0xff000000) << 8) | ((x >> 8) & 0xff000000); }\nstatic uint16_t tobe16( uint16_t x ) { return IS_BIG_ENDIAN ? x : swap16(x); }\nstatic uint32_t tobe32( uint32_t x ) { return IS_BIG_ENDIAN ? x : swap32(x); }\nstatic uint64_t tobe64( uint64_t x ) { return IS_BIG_ENDIAN ? x : swap64(x); }\nstatic uint16_t tole16( uint16_t x ) { return IS_BIG_ENDIAN ? swap16(x) : x; }\nstatic uint32_t tole32( uint32_t x ) { return IS_BIG_ENDIAN ? swap32(x) : x; }\nstatic uint64_t tole64( uint64_t x ) { return IS_BIG_ENDIAN ? swap64(x) : x; }\n\n/*\n#include <stdio.h>\nint main() {\n    printf(\"%x\\n\", swap32(0x12345678) );\n}\n*/\n"
  },
  {
    "path": "tinyerror.c",
    "content": "// simple error handling api. non-intrusive version.\n// - rlyeh, public domain.\n// \n// Errors automatically printed in debug builds.\n// Usage: use return OK(retvalue) or return ERROR(retvalue, \"error\"...); as desired.\n// Usage: to check for errors: if(ERROR) { /* do something here */ }\n// Good habit: system errorcode first, then human explanation when reporting errors. Ie, ERROR(rc, \"404 File not found %s\\n\", file);\n\n#pragma once\n#include <stdio.h>\n\n#  if !defined ERROR_LOG && defined NDEBUG\n#define ERROR_LOG(...)       (void)0\n#elif !defined ERROR_LOG\n#define ERROR_LOG(...)       (fprintf(stderr, __VA_ARGS__), fprintf(stderr, \"\\n\"))\n#endif\n\n#define OK(retval)         (ERROR = (char*)0, (retval))\n#define ERROR(retval, ...) (ERROR_LOG(\"\" __VA_ARGS__), ERROR = (char*)\"Error: \" #__VA_ARGS__ \" (@\" __FUNCTION__ \" \" __FILE__ \":\" ERR0R(__LINE__) \") \", (retval))\n#define ERR0R(rc)           ERRoR(rc)\n#define ERRoR(rc)           #rc\n\n#  ifdef __GNUC__\n#define __FUNCTION__ \"\"\nstatic __thread char* ERROR = 0;\n#else // _MSC_VER\nstatic __declspec(thread) char* ERROR = 0;\n#endif\n\n#if 0 // demo\nint derefence(int *ptr) {\n    if(ptr) return OK(*ptr);\n    return ERROR(0, \"404: Cannot deference pointer [%p]\", ptr); // errorcode + variable message (ideal)\n    return ERROR(0, \"Cannot deference pointer [%p]\", ptr);      // dynamic message (no errorcode)\n    return ERROR(0, \"Cannot deference pointer\");                // fixed message (no errorcode)\n    return ERROR(0);                                            // (no message) (no errorcode)\n}\nint main(int arg, char **argv) {\n    int a = derefence(&arg); // pass\n    int b = derefence(NULL); // fail\n    if( ERROR ) { /* do something here */ }\n}\n#endif\n"
  },
  {
    "path": "tinyfsm.c",
    "content": "// Tiny FSM. rlyeh, public domain | wtrmrkrlyeh\n\n#pragma once\n#define with(st)        for(int i=1;i--;st[1]=st[0]) switch(((st[0])<<16)|(st[1]))\n#define when(a)         break; case (((a)<<16)|(a))\n#define transition(a,b) break; case (((b)<<16)|(a))\ntypedef int fsm[2];\n\n\n/*\n#include <stdio.h>\n\nenum {\n    IDLE,\n    WALKING,\n    RUNNING,\n};\n\nvoid update( fsm state ) {\n    with(state) {\n        when(IDLE):                  puts(\"idle\");\n        transition(IDLE,WALKING):    puts(\"idle --> walking\");\n        transition(IDLE,RUNNING):    puts(\"idle --> running\");\n\n        when(WALKING):               puts(\"walking\");\n        transition(WALKING,IDLE):    puts(\"walking --> idle\");\n        transition(WALKING,RUNNING): puts(\"walking --> running\");\n\n        when(RUNNING):               puts(\"running\");\n        transition(RUNNING,IDLE):    puts(\"running --> idle\");\n        transition(RUNNING,WALKING): puts(\"running --> walking\");\n    }\n}\n\nint main() {\n    fsm state = {0};\n\n    *state = IDLE;\n    update(state);\n\n    *state = WALKING;\n    update(state);\n\n    *state = WALKING;\n    update(state);\n\n    *state = RUNNING;\n    update(state);\n\n    *state = IDLE;\n    update(state);\n}\n*/\n"
  },
  {
    "path": "tinygc.cc",
    "content": "// tiny garbage collector (<100 LOCs). Genius code tricks by @orangeduck (see: https://github.com/orangeduck/tgc README)\n// - rlyeh, public domain.\n\nvoid  gc_init(void *argc, int initial_mbytes_reserved); // pointer to argc (from main), and initial MiB reserved\nvoid  gc_run(void);                                     // mark & sweep\nvoid  gc_stop(void);                                    // sweep\n\nvoid* gc_malloc(int sz);                                // allocator\nchar* gc_strdup(const char *str);                       // util\n\n// macro that forbids pointer arithmetic (enables fixed pointer addresses)\n#define GC(type) type const \n\n// ---\n\n#include <setjmp.h> // setjmp, jmp_buf\n#include <stdlib.h> // realloc\n#include <string.h> // memcpy, strlen\n#include <stdio.h>  // printf\n#include <stdint.h> // uintptr_t, UINTPTR_MAX\n#include <set>      // std::set<>\n#include <vector>   // std::vector<>\n\n#ifndef GC_REALLOC\n#define GC_REALLOC realloc\n#endif\n\nstatic std::set<void*> gc_inuse;\nstatic std::vector<void*> gc_spawned;\nstatic void *gc_top = 0, *gc_min = 0, *gc_max = (void*)UINTPTR_MAX;\n\nstatic void gc_mark_stack(void) {\n    void *bot = gc_top, *top = &bot, *last = 0;\n\n    for( void *p = bot<top?bot:top, *e = bot<top?top:bot; p < e; p = (char*)p + sizeof(void*) ) {\n        void *ptr = *((void**)p);\n\n        if( ptr == last  ) continue; // already checked\n        if( ptr < gc_min ) continue; // out of gc_spawned bounds. also, nullptr check included here\n        if( ptr > gc_max ) continue; // out of gc_spawned bounds.\n        if( (uintptr_t)ptr & 0x7 ) continue; // 64-bit unaligned (not a pointer).\n\n        gc_inuse.insert(last = ptr);\n    }\n}\nstatic void gc_mark() { // mark reachable stack pointers\n    jmp_buf env = {0};\n    void (*volatile check)(void) = gc_mark_stack;\n    setjmp(env);\n    check();\n}\nstatic void gc_sweep() { // sweep unreachable stack pointers\n    gc_min = (void*)UINTPTR_MAX, gc_max = 0;\n\n    size_t back = gc_spawned.size();\n    for( size_t i = 0; i < back; ++i) {\n        void *ptr = gc_spawned[i];\n\n        if( ptr > gc_max ) gc_max = ptr;\n        if( ptr < gc_min ) gc_min = ptr;\n\n        bool used = gc_inuse.find(ptr) != gc_inuse.end();\n        if( !used ) {\n            GC_REALLOC(gc_spawned[i], 0); //free\n\n            void *swap = gc_spawned[--back]; // vector erase\n            gc_spawned[back] = gc_spawned[i];\n            gc_spawned[i--] = swap;\n        }\n    }\n\n    size_t collected = gc_spawned.size() - back;\n    if( collected ) printf(\"gc: %9d objects collected\\n\", (int)collected);\n\n    gc_spawned.resize( back );\n    gc_inuse.clear();\n}\n\nvoid gc_init(void *argc, int MiB) {\n    gc_top = argc;\n    gc_spawned.reserve((MiB > 0) * MiB * 1024 * 1024 / sizeof(void*));\n}\nvoid gc_run() {\n    gc_mark();\n    gc_sweep();\n}\nvoid gc_stop() {\n    gc_sweep();\n}\n\nvoid *gc_malloc( int sz ) {\n    void *ptr = GC_REALLOC(0, sz); // malloc\n    if( ptr ) gc_spawned.push_back(ptr);\n    return ptr;\n}\nchar *gc_strdup( const char *s ) {\n    int bytes = (int)strlen(s)+1;\n    return (char *)memcpy(gc_malloc(bytes), s, bytes);\n}\n\n/*\n#include <time.h>\n#define benchmark(t,...) for(clock_t beg=clock(), end=beg-beg; !end; printf(\"\" __VA_ARGS__), printf(\" %5.2fs\\n\", t=((end=clock()-beg) / (double)CLOCKS_PER_SEC)))\n\nvoid bench() {\n    enum { FRAMES = 30, COUNT = 1000000 };\n\n    double baseline;\n    benchmark(baseline, \"%2.1fM allocs+frees (baseline; regular malloc)\", FRAMES * COUNT * 2 / 1000000.0) {\n        for( int frame = 0; frame < FRAMES; ++frame ) {\n            for( int n = 0; n < COUNT; ++n ) {\n                free( malloc(16) );\n            }\n        }\n    }\n\n    double gctime;\n    benchmark(gctime, \"%2.1fM allocs+frees (gc)\", FRAMES * COUNT * 2 / 1000000.0) {\n        for( int frame = 0; frame < FRAMES; ++frame ) {\n            for( int n = 0; n < COUNT; ++n ) {\n                (void)gc_malloc(16);\n            }\n        }\n        gc_run();\n    }\n\n         if(baseline<=gctime) printf(\"gc is x%.2f times slower\\n\", gctime/baseline);\n    else if(baseline >gctime) printf(\"gc is x%.2f times faster!\\n\", baseline/gctime);\n}\n\nvoid demo() {\n    GC(void*) memory = gc_malloc(1024); (void)memory;     // will be collected\n    GC(char*) string = gc_strdup(\"hello world\");          // will be collected\n    GC(char*) x = gc_strdup(\"Hi\"); x[0] |= 32;            // will be collected. note: indexing is ok; pointer arithmetic is forbidden.\n    gc_run();\n\n    puts(string);\n    gc_run();\n}\n\nint main(int argc, char **argv) {\n    gc_init(&argc, 256); (void)argv;\n\n    demo();\n    bench();\n\n    gc_stop();\n}\n*/\n"
  },
  {
    "path": "tinyhexbase.c",
    "content": "// hexBASE \n// Very simple binary to ascii encoding. 0 to 2+100% bytes overhead (worst case)\n//\n// Specification:\n// if char in [32..126] range then print \"%c\", char ('~' escaped as \"~~\"),\n// else print \"~%02x[...]~\", for all remaining bytes.\n// \n// - rlyeh, public domain.\n\n#pragma once\n#include <stdio.h>\n\nstatic inline\nvoid hexbasenl( FILE *fp, const void *ptr, int len ) {\n    const unsigned char *buf = (const unsigned char*)ptr;\n    for( ; len-- > 0; buf++ ) {\n        unsigned char chr = (unsigned char)*buf;\n        /**/ if( chr >= 32 && chr < 126 ) fprintf(fp, \"%c\", chr);\n        else if( chr == 126 )             fprintf(fp, \"%s\", \"~~\"); \n        else {\n            fprintf(fp, \"%c\", '~');\n            do fprintf(fp, \"%02x\", *buf++); while( len-- > 0 );\n            fprintf(fp, \"%c\", '~');\n        }\n    }\n}\n\nstatic inline\nvoid hexbase( FILE *fp, const void *ptr, int len ) {\n    hexbasenl(fp, ptr, len);\n    fprintf(fp, \"%s\\n\", \"\");\n}\n\n/*\n#include <string.h>\nint main() {\n    hexbase( stdout, \"hello world\", strlen(\"hello world\") );                   // --> hello world\n    hexbase( stdout, \"hello world \\x1\\x2\\x3\\xff\", strlen(\"hello world\") + 5 ); // --> hello world ~010203ff~\n    hexbase( stdout, \"hello~world\", strlen(\"hello~world\") );                   // --> hello~~world\n    hexbase( stdout, \"\\xa1\\2\\3\", 3 );                                          // --> ~a10203~\n    hexbase( stdout, \"\\1\\2\\3hello world\", 3 + strlen(\"hello world\") );         // --> ~01020368656c6c6f20776f726c64~\n    hexbase( stdout, \"\\1\\2\\3hello world\\xf0\", 4 + strlen(\"hello world\") );     // --> ~01020368656c6c6f20776f726c64f0~\n}\n*/\n"
  },
  {
    "path": "tinyhexdump.c",
    "content": "// Tiny hexdump viewer. rlyeh, public domain | wtrmrkrlyeh\n#include <stdio.h>\n\nvoid hexdump( FILE *fp, const void *ptr, unsigned len, int width ) {\n    unsigned char *data = (unsigned char*)ptr;\n    for( unsigned jt = 0; jt < len; jt += width ) {\n        fprintf( fp, \"; %05d \", jt );\n        for( unsigned it = jt, next = it + width; it < len && it < next; ++it ) {\n            fprintf( fp, \"%02x %s\", (unsigned char)data[it], &\" \\n\\0...\\n\"[ (1+it) < len ? 2 * !!((1+it) % width) : 3 ] );\n        }\n        fprintf( fp, \"; %05d \", jt );\n        for( unsigned it = jt, next = it + width; it < len && it < next; ++it ) {\n            fprintf( fp, \" %c %s\", (signed char)data[it] >= 32 ? (signed char)data[it] : (signed char)'.', &\" \\n\\0...\\n\"[ (1+it) < len ? 2 * !!((1+it) % width) : 3 ] );\n        }\n    }\n}\n\n/*\n#include <string.h>\nint main() {\n    const char *sample = __FILE__ \"/\" __TIME__ \"/\" __DATE__;\n    hexdump( stdout, sample, strlen(sample), 16 );\n}\n*/\n"
  },
  {
    "path": "tinyhuman.hpp",
    "content": "// tiny de/humanized numbers. based on freebsd implementation.\n// - rlyeh, public domain | wtrmrkrlyeh\n\n#pragma once\n#include <string>\n#include <stdint.h>\n\ninline std::string humanize( uint64_t num, const char *suffix = \" \" ) {\n    const char prefixes[] = \" KMGTPE\";\n    const char* prefixp = prefixes;\n    uint64_t i = num, d = 0;\n    while( (i > 1024) && *prefixp++ ) {\n        d = (i % 1024) / 10, i /= 1024;\n    }\n    if (d > 0) return std::to_string(i) + '.' + std::to_string(d) + suffix + *prefixp;\n    else       return std::to_string(i) + suffix + *prefixp;\n}\n\ninline uint64_t dehumanize( const std::string &str ) {\n    size_t sz = 1, mul = 0;\n    double num = std::stof(str, &sz);\n    while( str[sz] && str[sz] == ' ' ) sz++;\n    switch( str[sz] ) {\n        default: case 'B': case 'b': mul = 0;\n        break;   case 'K': case 'k': mul = 1;\n        break;   case 'M': case 'm': mul = 2;\n        break;   case 'G': case 'g': mul = 3;\n        break;   case 'T': case 't': mul = 4;\n        break;   case 'P': case 'p': mul = 5;\n        break;   case 'E': case 'e': mul = 6; // may overflow\n    }\n    while( mul-- ) if( num * 1024 < num ) return 0; else num *= 1024;\n    return num;\n}\n\n/*\n#include <iostream>\nint main() {\n    std::cout << __LINE__ << \" \" << humanize(1238) << \"m\" << std::endl;\n    std::cout << __LINE__ << \" \" << humanize(123823) << \"l\" << std::endl;\n    std::cout << __LINE__ << \" \" << humanize(123828328) << \"bytes\" << std::endl;\n    std::cout << \"---\" << std::endl;\n\n    std::cout << __LINE__ << \" \" << dehumanize(\"118 km\") << std::endl;\n    std::cout << __LINE__ << \" \" << dehumanize(\"118.9M\") << std::endl;\n    std::cout << __LINE__ << \" \" << dehumanize(\"118M\") << std::endl;\n    std::cout << __LINE__ << \" \" << dehumanize(\"118b\") << std::endl;\n    std::cout << __LINE__ << \" \" << dehumanize(\"118k\") << std::endl;\n    std::cout << __LINE__ << \" \" << dehumanize(\"118mb\") << std::endl;\n    std::cout << __LINE__ << \" \" << dehumanize(\"118gb\") << std::endl;\n    std::cout << __LINE__ << \" \" << dehumanize(\"118tb\") << std::endl;\n    std::cout << __LINE__ << \" \" << dehumanize(\"118pb\") << std::endl;\n}\n*/\n"
  },
  {
    "path": "tinyini.c",
    "content": "// ini+, extended ini format \n// - rlyeh, public domain\n//\n// # spec\n//\n//   ; line comment\n//   [details]          ; map section name (optional)\n//   user=john          ; key and value (mapped here as details.user=john)\n//   +surname=doe jr.   ; sub-key and value (mapped here as details.user.surname=doe jr.)\n//   color=240          ; key and value \\\n//   color=253          ; key and value |> array: color[0], color[1] and color[2]\n//   color=255          ; key and value /\n//   color=             ; remove key/value(s)\n//   color=white        ; recreate key; color[1] and color[2] no longer exist\n//   []                 ; unmap section\n//   -note=keys may start with symbols (except plus and semicolon)\n//   -note=linefeeds are either \\r, \\n or \\r\\n.\n//   -note=utf8 everywhere.\n//\n\n#pragma once\n\n// api\n\nchar *ini( const char *text );\n\n// api, alternate callback version\n\nvoid ini_cb( const char *text, void (*yield)( const char *key, const char *value, void *userdata ), void *userdata );\n\n// impl\n\n#include <stdio.h>\n#include <stdlib.h>\n\nstatic char *ini( const char *s ) {\n    char *map = 0;\n    int mapcap = 0, maplen = 0;\n    enum { DEL, REM, TAG, KEY, SUB, VAL } fsm = DEL;\n    const char *cut[6] = {0}, *end[6] = {0};\n    while( *s ) {\n        while( *s && (*s == ' ' || *s == '\\t' || *s == '\\r' || *s == '\\n') ) ++s;\n        /**/ if( *s == ';' ) cut[fsm = REM] = ++s;\n        else if( *s == '[' ) cut[fsm = TAG] = ++s;\n        else if( *s == '+' ) cut[fsm = SUB] = ++s;\n        else if( *s == '=' ) cut[fsm = VAL] = ++s;\n        else if( *s > ' ' && *s <= 'z' && *s != ']' ) cut[fsm = KEY] = cut[SUB] = end[SUB] = s;\n        else { ++s; continue; }\n        /**/ if( fsm == REM ) { while(*s && *s != '\\r'&& *s != '\\n') ++s; }\n        else if( fsm == TAG ) { while(*s && *s != '\\r'&& *s != '\\n'&& *s != ']') ++s; end[fsm] = s; }\n        else if( fsm == KEY ) { while(*s && *s >  ' ' && *s <= 'z' && *s != '=') ++s; end[fsm] = s; }\n        else if( fsm == SUB ) { while(*s && *s >  ' ' && *s <= 'z' && *s != '=') ++s; end[fsm] = s; }\n        else if( fsm == VAL ) { while(*s && *s >= ' ' && *s <= 'z' && *s != ';') ++s; end[fsm] = s;\n            while( end[fsm][-1] == ' ' ) --end[fsm];\n            char buf[256] = {0}, *key = buf;\n            if( end[TAG] - cut[TAG] ) key += sprintf(key, \"%.*s.\", (int)(end[TAG] - cut[TAG]), cut[TAG] );\n            if( end[KEY] - cut[KEY] ) key += sprintf(key,  \"%.*s\", (int)(end[KEY] - cut[KEY]), cut[KEY] );\n            if( end[SUB] - cut[SUB] ) key += sprintf(key, \".%.*s\", (int)(end[SUB] - cut[SUB]), cut[SUB] );\n            int reqlen = (key - buf) + 1 + (end[VAL] - cut[VAL]) + 1 + 1;\n            if( (reqlen + maplen) >= mapcap ) map = realloc( map, mapcap += reqlen + 512 );\n            sprintf( map + maplen, \"%.*s%c%.*s%c%c\", (int)(key - buf), buf, 0, (int)(end[VAL] - cut[VAL]), cut[VAL], 0, 0 );\n            maplen += reqlen - 1;\n        }\n    }\n    return map;\n}\n\nstatic void ini_cb( const char *text, void (*yield)( const char *key, const char *value, void *userdata ), void *userdata ) {\n    char *kv = ini( text );\n    if( kv ) {\n        for( char *iter = kv; iter[0]; ) {\n            const char *key = iter; while( *iter++ );\n            const char *val = iter; while( *iter++ );\n            yield( key, val, userdata );\n        }\n        free( kv );\n    }\n}\n\n\n/*\nint main() {\n\n    char *kv = ini(\n        \"; line comment\\n\"\n        \"[details]          ; map section name (optional)\\n\"\n        \"user=john          ; key and value (mapped here as details.user=john)\\n\"\n        \"+surname=doe jr.   ; sub-key and value (mapped here as details.user.surname=doe jr.)\\n\"\n        \"color=240          ; key and value \\\\\\n\"\n        \"color=253          ; key and value |> array: color[0], color[1] and color[2]\\n\"\n        \"color=255          ; key and value /\\n\"\n        \"color=             ; remove key/value(s)\\n\"\n        \"color=white        ; recreate key; color[1] and color[2] no longer exist\\n\"\n        \"[]                 ; unmap section\\n\"\n        \"-note=keys may start with symbols (except plus and semicolon)\\n\"\n        \"-note=linefeeds are either \\\\r, \\\\n or \\\\r\\\\n.\\n\"\n        \"-note=utf8 everywhere.\\n\"\n    );\n\n    if( kv ) {\n        for( char *iter = kv; iter[0]; ) {\n            printf(\"key: '%s', \", iter); while( *iter++ );\n            printf(\"val: '%s'\\n\", iter); while( *iter++ );\n        }\n        free( kv );\n    }\n}\n*/\n"
  },
  {
    "path": "tinyjson5.c",
    "content": "// JSON5 + SJSON parser module\n//\n// License:\n// This software is dual-licensed to the public domain and under the following\n// license: you are granted a perpetual, irrevocable license to copy, modify,\n// publish, and distribute this file as you see fit.\n// No warranty is implied, use at your own risk.\n//\n// Credits:\n// Dominik Madarasz (original code) (GitHub: zaklaus)\n// r-lyeh (fork)\n\n#ifndef JSON5_H\n#define JSON5_H\n\n#ifndef JSON5_ASSERT\n#define JSON5_ASSERT do { printf(\"JSON5: Error L%d while parsing '%c' in '%.16s'\\n\", __LINE__, p[0], p); assert(0); } while(0)\n#endif\n\n#ifndef JSON5_REALLOC\n#define JSON5_REALLOC realloc\n#endif\n\n#include <stdint.h>\n#include <stdio.h>\n\ntypedef enum json5_type {\n    json5_undefined,\n    json5_null,\n    json5_bool,\n    json5_object,\n    json5_string,\n    json5_array,\n    json5_integer,\n    json5_real,\n} json5_type;\n\ntypedef struct json5 {\n    char*      name;\n    unsigned   type : 3;\n    unsigned   count : 29;\n    union {\n        struct json5* array;\n        struct json5* nodes;\n        int64_t   integer;\n        double    real;\n        char*     string;\n        int       boolean;\n    };\n} json5;\n\nchar* json5_parse(json5 *root, char *source, int flags);\nvoid  json5_write(FILE *fp, const json5 *root);\nvoid  json5_free(json5 *root);\n\n#endif // JSON5_H\n\n\n#ifdef JSON5_C\n#pragma once\n#include <assert.h>\n#include <ctype.h>\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n// vector library -------------------------------------------------------------\nsize_t vsize( void *p ) {\n    return p ? 0[ (size_t*)p - 2 ] : 0;\n}\nvoid *vresize( void *p, size_t sz ) {\n    size_t *ret = (size_t*)p - 2;\n    if( !p ) {\n        ret = (size_t*)JSON5_REALLOC( 0, sizeof(size_t) * 2 + sz );\n        ret[0] = sz;\n        ret[1] = 0;\n    } else {\n        size_t osz = ret[0];\n        size_t ocp = ret[1];\n        if( sz <= (osz + ocp) ) {\n            ret[0] = sz;\n            ret[1] = ocp - (sz - osz);\n        } else {\n            ret = (size_t*)JSON5_REALLOC( ret, sizeof(size_t) * 2 + sz * 1.75 );\n            ret[0] = sz;\n            ret[1] = (size_t)(sz * 1.75) - sz;\n        }\n    }\n    return &ret[2];\n}\nvoid *vrealloc( void *p, size_t sz ) {\n    if( sz ) {\n        return vresize( p, sz );\n    } else {\n        if( p ) {\n            size_t *ret = (size_t*)p - 2;\n            ret[0] = 0;\n            ret[1] = 0;\n            JSON5_REALLOC( ret, 0 );\n        }\n        return 0;\n    }\n}\n\n// array library --------------------------------------------------------------\n#ifndef array_cast\n#ifdef __cplusplus\n#define array_cast(x) (decltype(x))\n#else\n#define array_cast(x) (void *)\n#endif\n#define array_push(t, ...) ( (t) = array_cast(t) vrealloc((t), (array_count(t) + 1) * sizeof(0[t]) ), (t)[ array_count(t) - 1 ] = (__VA_ARGS__) )\n#define array_count(t) (int)( (t) ? vsize(t) / sizeof(0[t]) : 0u )\n#define array_free(t) ( array_cast(t) vrealloc((t), 0), (t) = 0 )\n#endif\n\n// json5 ----------------------------------------------------------------------\nchar *json5__trim(char *p) {\n    while (*p) {\n        /**/ if( isspace(*p) ) ++p;\n        else if( p[0] == '/' && p[1] == '*' ) { // skip C comment\n            for( p += 2; *p && !(p[0] == '*' && p[1] == '/'); ++p) {}\n            if( *p ) p += 2;\n        }\n        else if( p[0] == '/' && p[1] == '/' ) { // skip C++ comment\n            for( p += 2; *p && p[0] != '\\n'; ++p) {}\n            if( *p ) ++p;\n        }\n        else break;\n    }\n    return p;\n}\n\nchar *json5__parse_value(json5 *obj, char *p, char **err_code);\n\nchar *json5__parse_string(json5 *obj, char *p, char **err_code) {\n    assert(obj && p);\n\n    if( *p == '\"' || *p == '\\'' || *p == '`' ) {\n        obj->type = json5_string;\n        obj->string = p + 1;\n\n        char eos_char = *p, *b = obj->string, *e = b;\n        while (*e) {\n            /**/ if( *e == '\\\\' && (e[1] == eos_char) ) ++e;\n            else if( *e == '\\\\' && (e[1] == '\\r' || e[1] == '\\n') ) *e = ' ';\n            else if( *e == eos_char ) break;\n            ++e;\n        }\n\n        *e = '\\0';\n        return p = e + 1;\n    }\n\n    //JSON5_ASSERT; *err_code = \"json5_error_invalid_value\";\n    return NULL;\n}\n\nchar *json5__parse_object(json5 *obj, char *p, char **err_code) {\n    assert(obj && p);\n\n    if( 1 /* *p == '{' */ ) { /* <-- for SJSON */\n        int skip = *p == '{'; /* <-- for SJSON */\n\n        obj->type = json5_object;\n\n        while (*p) {\n            json5 node = { 0 };\n            \n            do { p = json5__trim(p + skip); skip = 1; } while( *p == ',' );\n\n            if( *p == '}' ) {\n                ++p;\n                break;\n            }\n            // @todo: is_unicode() (s[0] == '\\\\' && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]))) {\n            else if( isalpha(*p) || *p == '_' || *p == '$' ) { // also || is_unicode(p)\n                node.name = p;\n\n                do {\n                    ++p;\n                } while (*p && (*p == '_' || isalpha(*p) || isdigit(*p)) ); // also || is_unicode(p)\n\n                char *e = p;\n                p = json5__trim(p);\n                *e = '\\0';\n            }\n            else { //if( *p == '\"' || *p == '\\'' || *p == '`' ) {\n                char *ps = json5__parse_string(&node, p, err_code);\n                if( !ps ) {\n                    return NULL;\n                }\n                p = ps;\n                node.name = node.string;\n                p = json5__trim(p);\n            }\n\n            // @todo: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6\n            if( !(node.name && node.name[0]) ) { // !json5__validate_name(node.name) ) {\n                JSON5_ASSERT; *err_code = \"json5_error_invalid_name\";\n                return NULL;\n            }\n\n            if( !p || (*p && (*p != ':' && *p != '=' /* <-- for SJSON */)) ) {\n                JSON5_ASSERT; *err_code = \"json5_error_invalid_name\";\n                return NULL;\n            }\n            p = json5__trim(p + 1);\n            p = json5__parse_value(&node, p, err_code);\n\n            if( *err_code[0] ) {\n                return NULL;\n            }\n\n            if( node.type != json5_undefined ) {\n                array_push(obj->nodes, node);\n                ++obj->count;\n            }\n\n            if( *p == '}') { ++p; break; }\n        }\n\n        return p;\n    }\n\n    JSON5_ASSERT; *err_code = \"json5_error_invalid_value\";\n    return NULL;\n}\n\nchar *json5__parse_value(json5 *obj, char *p, char **err_code) {\n    assert(obj && p);\n\n    p = json5__trim(p);\n\n    char *is_string = json5__parse_string(obj, p, err_code);\n\n    if( is_string ) {\n        p = is_string;\n        if( *err_code[0] ) {\n            return NULL;\n        }\n    }\n    else if( *p == '{' ) {\n        p = json5__parse_object( obj, p, err_code );\n        if( *err_code[0] ) {\n            return NULL;\n        }\n    }\n    else if( *p == '[' ) {\n        obj->type = json5_array;\n\n        while (*p) {\n            json5 elem = { 0 };\n\n            do { p = json5__trim(p + 1); } while( *p == ',' );\n            if( *p == ']') { ++p; break; }\n\n            p = json5__parse_value(&elem, p, err_code);\n\n            if( *err_code[0] ) {\n                return NULL;\n            }\n\n            if( elem.type != json5_undefined ) {\n                array_push(obj->array, elem);\n                ++obj->count;\n            }\n            if (*p == ']') { ++p; break; }\n        }\n    }\n    else if( isalpha(*p) || (*p == '-' && !isdigit(p[1])) ) {\n        const char *labels[] = { \"null\", \"on\",\"true\", \"off\",\"false\", \"nan\",\"NaN\", \"-nan\",\"-NaN\", \"inf\",\"Infinity\", \"-inf\",\"-Infinity\" };\n        const int lenghts[] = { 4, 2,4, 3,5, 3,3, 4,4, 3,8, 4,9 };\n        for( int i = 0; labels[i]; ++i ) {\n            if( !strncmp(p, labels[i], lenghts[i] ) ) {\n                p += lenghts[i];\n#ifdef _MSC_VER // somehow, NaN is apparently signed in MSC\n                /**/ if( i >= 5 ) obj->type = json5_real, obj->real = i >= 11 ? -INFINITY : i >= 9 ? INFINITY : i >= 7 ?  NAN :-NAN;\n#else\n                /**/ if( i >= 5 ) obj->type = json5_real, obj->real = i >= 11 ? -INFINITY : i >= 9 ? INFINITY : i >= 7 ? -NAN : NAN;\n#endif\n                else if( i >= 1 ) obj->type = json5_bool, obj->boolean = i <= 2;\n                else              obj->type = json5_null;\n                break;\n            }\n        }\n        if( obj->type == json5_undefined ) {\n            JSON5_ASSERT; *err_code = \"json5_error_invalid_value\";\n            return NULL;\n        }\n    }\n    else if( isdigit(*p) || *p == '+' || *p == '-' || *p == '.' ) {\n        char buffer[16] = {0}, *buf = buffer, is_hex = 0, is_dbl = 0;\n        while( *p && strchr(\"+-.xX0123456789aAbBcCdDeEfF\", *p)) {\n            is_hex |= (*p | 32) == 'x';\n            is_dbl |= *p == '.';\n            *buf++ = *p++;\n        }\n        obj->type = is_dbl ? json5_real : json5_integer;\n        /**/ if( is_dbl ) sscanf( buffer, \"%lf\", &obj->real );\n        else if( is_hex ) sscanf( buffer, \"%llx\", &obj->integer ); // SCNx64 -> inttypes.h\n        else              sscanf( buffer, \"%lld\", &obj->integer ); // SCNd64 -> inttypes.h\n    }\n    else {\n        return NULL;\n    }\n    return p;\n}\n\nchar *json5_parse(json5 *root, char *p, int flags) {\n    assert(root && p);\n\n    char *err_code = \"\";\n    *root = (json5) {0};\n\n    p = json5__trim(p);\n    if( *p == '[' ) { /* <-- for SJSON */\n        json5__parse_value(root, p, &err_code);\n    } else {\n        json5__parse_object(root, p, &err_code); /* <-- for SJSON */\n    }\n\n    return err_code[0] ? err_code : 0;\n}\n\nvoid json5_free(json5 *root) {\n    if( root->type == json5_array && root->array ) {\n        for( int i = 0, cnt = array_count(root->array); i < cnt; ++i ) {\n            json5_free(root->array + i);\n        }\n        array_free(root->array);\n    } \n\n    if( root->type == json5_object && root->nodes ) {\n        for( int i = 0, cnt = array_count(root->nodes); i < cnt; ++i ) {\n            json5_free(root->nodes + i);\n        }\n        array_free(root->nodes);\n    }\n\n    *root = (json5) {0}; // needed?\n}\n\nvoid json5_write(FILE *fp, const json5 *o) {\n#ifdef _MSC_VER\n    static __declspec(thread) int indent = 0;\n#else\n    static THREAD_LOCAL int indent = 0;\n#endif\n    static const char *tabs = \n        \"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\" \"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\"\n        \"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\" \"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\";\n    if( o->name ) {\n        fprintf(fp, \"%.*s\\\"%s\\\": \", indent, tabs, o->name);\n    }\n    /**/ if( o->type == json5_null ) fprintf(fp, \"%s\", \"null\");\n    else if( o->type == json5_bool ) fprintf(fp, \"%s\", o->boolean ? \"true\" : \"false\");\n    else if( o->type == json5_integer ) fprintf(fp, \"%lld\", o->integer);\n    else if( o->type == json5_real ) {\n        /**/ if( isnan(o->real) ) fprintf(fp, \"%s\", signbit(o->real) ? \"-nan\" : \"nan\" );\n        else if( isinf(o->real) ) fprintf(fp, \"%s\", signbit(o->real) ? \"-inf\" : \"inf\" );\n        else fprintf(fp, \"%.4llf\", o->real);\n    }\n    else if( o->type == json5_string ) { // write (escaped) string\n        char chars[] = \"\\\\\\\"\\n\\r\\b\\f\\v\", remap[] = \"\\\\\\\"nrbfv\", esc[256];\n        for( int i = 0; chars[i]; ++i ) esc[ chars[i] ] = remap[i];\n\n        const char *b = o->string, *e = strpbrk(b, chars), *sep = \"\\\"\";\n        while( e ) {\n            fprintf(fp, \"%s%.*s\\\\%c\", sep, (int)(e - b), b, esc[(unsigned char)*e] );\n            e = strpbrk( b = e + 1, chars);\n            sep = \"\";\n        }\n        fprintf(fp, \"%s%s\\\"\", sep, b);\n    }\n    else if( o->type == json5_array ) {\n        const char *sep = \"\";\n        fprintf(fp, \"%s\", \"[ \");\n        for( int i = 0, cnt = o->count; i < cnt; ++i ) {\n            fprintf(fp, \"%s\", sep); sep = \", \";\n            json5_write(fp, o->array + i);\n        }\n        fprintf(fp, \"%s\", \" ]\");\n    }\n    else if( o->type == json5_object ) {\n        const char *sep = \"\";\n        fprintf(fp, \"%.*s{\\n\", 0 * (++indent), tabs);\n        for( int i = 0, cnt = o->count; i < cnt; ++i ) {\n            fprintf(fp, \"%s\", sep); sep = \",\\n\";\n            json5_write(fp, o->nodes + i);\n        }\n        fprintf(fp, \"\\n%.*s}\", --indent, tabs);\n    } else {\n        char p[16] = {0};\n        JSON5_ASSERT; /* \"json5_error_invalid_value\"; */\n    }\n}\n#endif // JSON5_C\n\n#ifdef JSON5_BENCH\n#include <time.h>\nint main() {\n    // https://www.reddit.com/r/datasets/comments/1uyd0t/200000_jeopardy_questions_in_a_json_file/\n    char *content = 0;\n    for( FILE *fp = fopen(\"jeopardy.json\", \"rb\"); fp; fclose(fp), fp = 0 ) {\n        fseek(fp, 0L, SEEK_END);\n        size_t pos = ftell(fp);\n        fseek(fp, 0L, SEEK_SET);\n        content = (char*)malloc( pos + 1 );\n        fread(content, 1, pos, fp);\n        content[pos] = 0;\n    }\n\n    if( content ) {\n        clock_t start = clock();\n        json5 root = {0};\n        char *error = json5_parse(&root, content, 0);\n        clock_t end = clock();\n        double delta = ( end - start ) / (double)CLOCKS_PER_SEC;\n\n        if( !error ) {\n            printf(\"Parsing time: %.3fms\\n\", delta*1000);\n            printf(\"Total nodes: %d\\n\", array_count(root.array));\n            printf(\"Category: %s, air date: %s\\nQuestion: %s\\n\", root.array[0].nodes[0].string,\n                   root.array[0].nodes[1].string,\n                   root.array[0].nodes[2].string);\n        } else {\n            printf(\"Error: %s\\n\", error);\n        }\n\n        json5_free(&root);\n        free(content);\n    }\n}\n#endif\n\n#ifdef JSON5_DEMO\nint main() {\n    char source5[] = \n    \"  // comments\\n\" /* json5 sample */\n    \"  unquoted: 'and you can quote me on that',\\n\"\n    \"  singleQuotes: 'I can use \\\"double quotes\\\" here',\\n\"\n    \"  lineBreaks : \\\"Look, Mom! \\\\\\n\"\n    \"No \\\\n's!\\\",\\n\"\n    \"  hexadecimal: 0x100,\\n\"\n    \"  leadingDecimalPoint: .8675309, andTrailing: 8675309.,\\n\"\n    \"  positiveSign: +1,\\n\"\n    \"  trailingComma: 'in objects', andIn: ['arrays', ],\\n\"\n    \"  \\\"backwardsCompatible\\\": \\\"with JSON\\\",\\n\"\n    \"\"\n    \"  ip = \\\"127.0.0.1\\\"\\n\" /* sjson sample */\n    \"  port = 8888\\n\"\n    \"\"\n    \"  /* comment //nested comment*/\\n\" /* tests */\n    \"  // comment /*nested comment*/\\n\"\n    \"  nil: null,\"\n    \"  \\\"+lšctžýáíé=:\\\": true,,,,\"\n    \"  huge: 2.2239333e5, \"\n    \"  array: [+1,2,-3,4,5],    \"\n    \"  hello: 'world /*comment in string*/ //again', \"\n    \"  abc: 42.67, def: false, \"\n    \"  children : { a: 1, b: 2, },\"\n    \"  invalids : [ nan, NaN, -nan, -NaN, inf, Infinity, -inf, -Infinity ],\"\n    \"\"\n    \"}\\n\";\n\n    json5 root = { 0 };\n    char *error = json5_parse(&root, source5, 0);\n    if( error ) {\n        printf(\"Error: %s\\n\", error);\n    } else {\n        json5_write(stdout, &root);\n    }\n    json5_free(&root);\n}\n#endif\n"
  },
  {
    "path": "tinylog.c",
    "content": "// Tiny logging utilities. rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <stdio.h>\n#include <time.h>\n\n#ifdef _WIN32\n#define TTY(ansi) \"\"\n#else\n#define TTY(ansi) ansi\n#endif\n\n#define TRACE(...) do { time_t t = time(0); printf(\"%s[TRACE %.8s]%s %s:%d \", TTY(\"\\27[34m\"), 11+ctime(&t), TTY(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define DEBUG(...) do { time_t t = time(0); printf(\"%s[DEBUG %.8s]%s %s:%d \", TTY(\"\\27[36m\"), 11+ctime(&t), TTY(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define INFO(...)  do { time_t t = time(0); printf(\"%s[INFO  %.8s]%s %s:%d \", TTY(\"\\27[32m\"), 11+ctime(&t), TTY(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define WARN(...)  do { time_t t = time(0); printf(\"%s[WARN  %.8s]%s %s:%d \", TTY(\"\\27[33m\"), 11+ctime(&t), TTY(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define ERROR(...) do { time_t t = time(0); printf(\"%s[ERROR %.8s]%s %s:%d \", TTY(\"\\27[31m\"), 11+ctime(&t), TTY(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define FATAL(...) do { time_t t = time(0); printf(\"%s[FATAL %.8s]%s %s:%d \", TTY(\"\\27[35m\"), 11+ctime(&t), TTY(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n\n/*\nint main() {\n    FATAL(\"Hello %d\\n\", 123);\n    ERROR(\"Hello %d\\n\", 123);\n    WARN(\"Hello %d\\n\", 123);\n    INFO(\"Hello %d\\n\", 123);\n    DEBUG(\"Hello %d\\n\", 123);\n    TRACE(\"Hello %d\\n\", 123);\n}\n*/\n"
  },
  {
    "path": "tinylog.h",
    "content": "// Tiny logging utilities. rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <stdio.h>\n#include <time.h>\n\n#ifdef _WIN32\n#define ANSI(code) \"\"\n#else\n#define ANSI(code) code\n#endif\n\n#define TRACE(...) do { time_t t = time(0); printf(\"%s[TRACE %.8s]%s %s:%d \", ANSI(\"\\27[34m\"), 11+ctime(&t), ANSI(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define DEBUG(...) do { time_t t = time(0); printf(\"%s[DEBUG %.8s]%s %s:%d \", ANSI(\"\\27[36m\"), 11+ctime(&t), ANSI(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define INFO(...)  do { time_t t = time(0); printf(\"%s[INFO  %.8s]%s %s:%d \", ANSI(\"\\27[32m\"), 11+ctime(&t), ANSI(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define WARN(...)  do { time_t t = time(0); printf(\"%s[WARN  %.8s]%s %s:%d \", ANSI(\"\\27[33m\"), 11+ctime(&t), ANSI(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define ERROR(...) do { time_t t = time(0); printf(\"%s[ERROR %.8s]%s %s:%d \", ANSI(\"\\27[31m\"), 11+ctime(&t), ANSI(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n#define FATAL(...) do { time_t t = time(0); printf(\"%s[FATAL %.8s]%s %s:%d \", ANSI(\"\\27[35m\"), 11+ctime(&t), ANSI(\"\\27[0m\"), __FILE__, __LINE__); printf(__VA_ARGS__); } while(0)\n\n/*\nint main() {\n    FATAL(\"Hello %d\\n\", 123);\n    ERROR(\"Hello %d\\n\", 123);\n    WARN(\"Hello %d\\n\", 123);\n    INFO(\"Hello %d\\n\", 123);\n    DEBUG(\"Hello %d\\n\", 123);\n    TRACE(\"Hello %d\\n\", 123);\n}\n*/\n"
  },
  {
    "path": "tinylogger.h",
    "content": "// simple logger. likely slow, though.\n// - rlyeh, public domain.\n//\n// - [x] colors based on content.\n// - [x] no logging categories. throughput flood configurable by percentage (see LOG_LEVEL var).\n// - [x] print fatal errors always. with optional callstack (see LOG_PRINT_STACK macro).\n\n#pragma once\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#  if !defined LOG_LEVEL && (defined NDEBUG || defined SHIPPING)\n#define LOG_LEVEL 0   //   0% - no messages logged (only fatal errors will)\n#elif !defined LOG_LEVEL\n#define LOG_LEVEL 100 // 100% - all messages logged\n#endif\n\n#ifndef LOG_TIMER\n#define LOG_TIMER() 0.0 /* user-defined apptime clock here */\n#endif\n\n#ifndef LOG_PRINT_STACK\n#define LOG_PRINT_STACK() /* user-defined callstack printer here */\n#endif\n\n#  if !defined LOG_ENABLE_ANSI && defined _WIN32\n#include <winsock2.h>\n#define LOG_ENABLE_ANSI() for(unsigned mode=0;!mode;mode=1) SetConsoleMode(GetStdHandle(-11), (GetConsoleMode(GetStdHandle(-11), &mode), mode|4))\n#elif !defined LOG_ENABLE_ANSI\n#define LOG_ENABLE_ANSI()\n#endif\n\n#define LOG(...) do { \\\n    static char must_log = -1; \\\n    static enum { undefined=-1, restore=0, r=31,g,y,b,p,t,w,inv=0x80 } color = undefined; \\\n    char buf[2048]; snprintf(buf, 2048, \"\" __VA_ARGS__); \\\n    if( color == undefined ) { \\\n        LOG_ENABLE_ANSI(); \\\n        char low[2048]; int i; for(i=0;buf[i];++i) low[i] = 32|buf[i]; low[i]='\\0'; \\\n        /**/ if( strstr(low,\"fatal\")|| strstr(low,\"panic\") || strstr(low,\"assert\") ) color=r|inv,must_log=1; \\\n        else if( strstr(low,\"fail\") || strstr(low,\"error\") ) color=r; \\\n        else if( strstr(low,\"warn\") || strstr(low,\"alert\") ) color=y; /*beware,caution*/ \\\n        else if( strstr(low,\"info\") || strstr(low,\"succe\") ) color=g; /*ok, no error*/ \\\n        else if( strstr(low,\"debug\") ) color=t; \\\n        else if( strstr(low,\"trace\") ) color=p; else color=restore; \\\n        if( must_log < 0 ) { /* original splitmix64 by Sebastiano Vigna (CC0)*/ \\\n            uint64_t z = (__LINE__ + __COUNTER__ + UINT64_C(0x9E3779B97F4A7C15)); \\\n            z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); \\\n            must_log = (unsigned)((z ^ (z >> 31)) % 100) < LOG_LEVEL; } } \\\n    if( must_log ) { \\\n        double timer = LOG_TIMER(); \\\n        if(color&0x80) fprintf(stderr, \"\\033[7m\"); \\\n        if(timer>0)fprintf(stderr, \"\\033[%dm%07.3fs %s (%s:%d)\", color&0x7f, timer, buf, __FILE__, __LINE__); \\\n        else       fprintf(stderr, \"\\033[%dm%s (%s:%d)\", color&0x7f, buf, __FILE__, __LINE__); \\\n        fprintf(stderr, \"\\033[%dm\\n\", restore); \\\n        if(color&0x7f == r) LOG_PRINT_STACK(); } \\\n} while(0)\n\n#if 0 // demo\nint main() {\n    LOG(\"Test 1 - normal message: hello world %d\", 123);\n    LOG(\"Test 2 - trace message\");\n    LOG(\"Test 3 - debug message\");\n    LOG(\"Test 4 - info message\");\n    LOG(\"Test 5 - warning message\");\n    LOG(\"Test 6 - error message\");\n    LOG(\"Test 7 - fatal error message (fatal errors are always printed, despite LOG_LEVEL var)\");\n}\n#endif\n"
  },
  {
    "path": "tinylogger.hpp",
    "content": "// Tiny session logger. rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <stdio.h>\n\n#ifdef SHIPPING\nstruct logger {\n    logger() {\n        fclose(stdout);\n    }\n};\n#else\nstruct logger {\n    logger() {\n#       if   defined(PSVITA)\n        freopen(\"host0://log_vita.txt\", \"a+t\", stdout);\n#       elif defined(PS3)\n        freopen(\"/app_home/log_ps3.txt\", \"a+t\", stdout);\n#       elif defined(PS4)\n        freopen(\"/hostapp/log_ps4.txt\", \"a+t\", stdout);\n#       else\n        freopen(\"log_desktop.txt\", \"a+t\", stdout);\n#       endif\n        // Flush automatically every 16 KiB from now\n        setvbuf(stdout, NULL, _IOFBF, 16 * 1024);\n        // Header\n        puts(\";; New session\");\n        fflush(stdout);\n    }\n    ~logger() {\n        fflush(stdout);\n    }\n};\n#endif\n\n/*\nint main() {\n    logger resident;\n    puts(\"hello world\");\n}\n*/\n"
  },
  {
    "path": "tinymatch.c",
    "content": "// tiny wildcard/pattern matching. Based on anonymous souce code (Rob Pike's ?).\n// - rlyeh. public domain | wtrmrkrlyeh\n\nstatic int match( const char *pattern, const char *str ) {\n    if( *pattern=='\\0' ) return !*str;\n    if( *pattern=='*' )  return match(pattern+1, str) || (*str && match(pattern, str+1));\n    if( *pattern=='?' )  return *str && (*str != '.') && match(pattern+1, str+1);\n    return (*str == *pattern) && match(pattern+1, str+1);\n}\n\n/*\n#include <stdio.h>\nint main() {\n    printf(\"%s\\n\", match(\"abc\", \"abc\") ? \"match!\" : \"not found\" );\n    printf(\"%s\\n\", match(\"abc*\", \"abc\") ? \"match!\" : \"not found\" );\n    printf(\"%s\\n\", match(\"*bc\", \"abc\") ? \"match!\" : \"not found\" );\n    printf(\"%s\\n\", match(\"*bc*\", \"abc\") ? \"match!\" : \"not found\" );\n    printf(\"%s\\n\", match(\"*b?d*\", \"abcdef\") ? \"match!\" : \"not found\" );\n}\n*/\n"
  },
  {
    "path": "tinymime.c",
    "content": "// tinymime. ported from https://github.com/sindresorhus/file-type (source is mit licensed)\n// - rlyeh, public domain\n\n#pragma once\n\nstatic const char *tinymime( const unsigned char *buf, size_t len ) {\n    if( !(buf && len > 60) ) {\n        return \"\"; // invalid\n    }\n\n    if (buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF) {\n        return \"jpg\";\n    }\n\n    if (buf[0] == 0x89 && buf[1] == 0x50 && buf[2] == 0x4E && buf[3] == 0x47) {\n        return \"png\";\n    }\n\n    if (buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46) {\n        return \"gif\";\n    }\n\n    if (buf[8] == 0x57 && buf[9] == 0x45 && buf[10] == 0x42 && buf[11] == 0x50) {\n        return \"webp\";\n    }\n\n    // needs to be before `tif` check\n    if (((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0) || (buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A)) && buf[8] == 0x43 && buf[9] == 0x52) {\n        return \"cr2\";\n    }\n\n    if ((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0) || (buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A)) {\n        return \"tif\";\n    }\n\n    if (buf[0] == 0x42 && buf[1] == 0x4D) {\n        return \"bmp\";\n    }\n\n    if (buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0xBC) {\n        return \"jxr\";\n    }\n\n    if (buf[0] == 0x38 && buf[1] == 0x42 && buf[2] == 0x50 && buf[3] == 0x53) {\n        return \"psd\";\n    }\n\n    // needs to be before `zip` check\n    if (buf[0] == 0x50 && buf[1] == 0x4B && buf[2] == 0x3 && buf[3] == 0x4 && buf[30] == 0x6D && buf[31] == 0x69 && buf[32] == 0x6D && buf[33] == 0x65 && buf[34] == 0x74 && buf[35] == 0x79 && buf[36] == 0x70 && buf[37] == 0x65 && buf[38] == 0x61 && buf[39] == 0x70 && buf[40] == 0x70 && buf[41] == 0x6C && buf[42] == 0x69 && buf[43] == 0x63 && buf[44] == 0x61 && buf[45] == 0x74 && buf[46] == 0x69 && buf[47] == 0x6F && buf[48] == 0x6E && buf[49] == 0x2F && buf[50] == 0x65 && buf[51] == 0x70 && buf[52] == 0x75 && buf[53] == 0x62 && buf[54] == 0x2B && buf[55] == 0x7A && buf[56] == 0x69 && buf[57] == 0x70) {\n        return \"epub\";\n    }\n\n    // needs to be before `zip` check\n    // assumes signed .xpi from addons.mozilla.org\n    if (buf[0] == 0x50 && buf[1] == 0x4B && buf[2] == 0x3 && buf[3] == 0x4 && buf[30] == 0x4D && buf[31] == 0x45 && buf[32] == 0x54 && buf[33] == 0x41 && buf[34] == 0x2D && buf[35] == 0x49 && buf[36] == 0x4E && buf[37] == 0x46 && buf[38] == 0x2F && buf[39] == 0x6D && buf[40] == 0x6F && buf[41] == 0x7A && buf[42] == 0x69 && buf[43] == 0x6C && buf[44] == 0x6C && buf[45] == 0x61 && buf[46] == 0x2E && buf[47] == 0x72 && buf[48] == 0x73 && buf[49] == 0x61) {\n        return \"xpi\";\n    }\n\n    if (buf[0] == 0x50 && buf[1] == 0x4B && (buf[2] == 0x3 || buf[2] == 0x5 || buf[2] == 0x7) && (buf[3] == 0x4 || buf[3] == 0x6 || buf[3] == 0x8)) {\n        return \"zip\";\n    }\n\n    if( len > 261 ) \n    if (buf[257] == 0x75 && buf[258] == 0x73 && buf[259] == 0x74 && buf[260] == 0x61 && buf[261] == 0x72) {\n        return \"tar\";\n    }\n\n    if (buf[0] == 0x52 && buf[1] == 0x61 && buf[2] == 0x72 && buf[3] == 0x21 && buf[4] == 0x1A && buf[5] == 0x7 && (buf[6] == 0x0 || buf[6] == 0x1)) {\n        return \"rar\";\n    }\n\n    if (buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x8) {\n        return \"gz\";\n    }\n\n    if (buf[0] == 0x42 && buf[1] == 0x5A && buf[2] == 0x68) {\n        return \"bz2\";\n    }\n\n    if (buf[0] == 0x37 && buf[1] == 0x7A && buf[2] == 0xBC && buf[3] == 0xAF && buf[4] == 0x27 && buf[5] == 0x1C) {\n        return \"7z\";\n    }\n\n    if (buf[0] == 0x78 && buf[1] == 0x01) {\n        return \"dmg\";\n    }\n\n    if (\n        (buf[0] == 0x0 && buf[1] == 0x0 && buf[2] == 0x0 && (buf[3] == 0x18 || buf[3] == 0x20) && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70) ||\n        (buf[0] == 0x33 && buf[1] == 0x67 && buf[2] == 0x70 && buf[3] == 0x35) ||\n        (buf[0] == 0x0 && buf[1] == 0x0 && buf[2] == 0x0 && buf[3] == 0x1C && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70 && buf[8] == 0x6D && buf[9] == 0x70 && buf[10] == 0x34 && buf[11] == 0x32 && buf[16] == 0x6D && buf[17] == 0x70 && buf[18] == 0x34 && buf[19] == 0x31 && buf[20] == 0x6D && buf[21] == 0x70 && buf[22] == 0x34 && buf[23] == 0x32 && buf[24] == 0x69 && buf[25] == 0x73 && buf[26] == 0x6F && buf[27] == 0x6D) ||\n        (buf[0] == 0x0 && buf[1] == 0x0 && buf[2] == 0x0 && buf[3] == 0x1C && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70 && buf[8] == 0x69 && buf[9] == 0x73 && buf[10] == 0x6F && buf[11] == 0x6D) ||\n        (buf[0] == 0x0 && buf[1] == 0x0 && buf[2] == 0x0 && buf[3] == 0x1c && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70 && buf[8] == 0x6D && buf[9] == 0x70 && buf[10] == 0x34 && buf[11] == 0x32 && buf[12] == 0x0 && buf[13] == 0x0 && buf[14] == 0x0 && buf[15] == 0x0)\n    ) {\n        return \"mp4\";\n    }\n\n    if ((buf[0] == 0x0 && buf[1] == 0x0 && buf[2] == 0x0 && buf[3] == 0x1C && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70 && buf[8] == 0x4D && buf[9] == 0x34 && buf[10] == 0x56)) {\n        return \"m4v\";\n    }\n\n    if (buf[0] == 0x4D && buf[1] == 0x54 && buf[2] == 0x68 && buf[3] == 0x64) {\n        return \"mid\";\n    }\n\n    // needs to be before the `webm` check\n    if (buf[31] == 0x6D && buf[32] == 0x61 && buf[33] == 0x74 && buf[34] == 0x72 && buf[35] == 0x6f && buf[36] == 0x73 && buf[37] == 0x6B && buf[38] == 0x61) {\n        return \"mkv\";\n    }\n\n    if (buf[0] == 0x1A && buf[1] == 0x45 && buf[2] == 0xDF && buf[3] == 0xA3) {\n        return \"webm\";\n    }\n\n    if (buf[0] == 0x0 && buf[1] == 0x0 && buf[2] == 0x0 && buf[3] == 0x14 && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70) {\n        return \"mov\";\n    }\n\n    if (buf[0] == 0x52 && buf[1] == 0x49 && buf[2] == 0x46 && buf[3] == 0x46 && buf[8] == 0x41 && buf[9] == 0x56 && buf[10] == 0x49) {\n        return \"avi\";\n    }\n\n    if (buf[0] == 0x30 && buf[1] == 0x26 && buf[2] == 0xB2 && buf[3] == 0x75 && buf[4] == 0x8E && buf[5] == 0x66 && buf[6] == 0xCF && buf[7] == 0x11 && buf[8] == 0xA6 && buf[9] == 0xD9) {\n        return \"wmv\";\n    }\n\n    if (buf[0] == 0x0 && buf[1] == 0x0 && buf[2] == 0x1 && (buf[3] >> 4) == 0xb ) { // buf[3].toString(16)[0] === 'b') {\n        return \"mpg\";\n    }\n\n    if ((buf[0] == 0x49 && buf[1] == 0x44 && buf[2] == 0x33) || (buf[0] == 0xFF && buf[1] == 0xfb)) {\n        return \"mp3\";\n    }\n\n    if ((buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70 && buf[8] == 0x4D && buf[9] == 0x34 && buf[10] == 0x41) || (buf[0] == 0x4D && buf[1] == 0x34 && buf[2] == 0x41 && buf[3] == 0x20)) {\n        return \"m4a\";\n    }\n\n    // needs to be before `ogg` check\n    if (buf[28] == 0x4F && buf[29] == 0x70 && buf[30] == 0x75 && buf[31] == 0x73 && buf[32] == 0x48 && buf[33] == 0x65 && buf[34] == 0x61 && buf[35] == 0x64) {\n        return \"opus\";\n    }\n\n    if (buf[0] == 0x4F && buf[1] == 0x67 && buf[2] == 0x67 && buf[3] == 0x53) {\n        return \"ogg\";\n    }\n\n    if (buf[0] == 0x66 && buf[1] == 0x4C && buf[2] == 0x61 && buf[3] == 0x43) {\n        return \"flac\";\n    }\n\n    if (buf[0] == 0x52 && buf[1] == 0x49 && buf[2] == 0x46 && buf[3] == 0x46 && buf[8] == 0x57 && buf[9] == 0x41 && buf[10] == 0x56 && buf[11] == 0x45) {\n        return \"wav\";\n    }\n\n    if (buf[0] == 0x23 && buf[1] == 0x21 && buf[2] == 0x41 && buf[3] == 0x4D && buf[4] == 0x52 && buf[5] == 0x0A) {\n        return \"amr\";\n    }\n\n    if (buf[0] == 0x25 && buf[1] == 0x50 && buf[2] == 0x44 && buf[3] == 0x46) {\n        return \"pdf\";\n    }\n\n    if (buf[0] == 0x4D && buf[1] == 0x5A) {\n        return \"exe\";\n    }\n\n    if ((buf[0] == 0x43 || buf[0] == 0x46) && buf[1] == 0x57 && buf[2] == 0x53) {\n        return \"swf\";\n    }\n\n    if (buf[0] == 0x7B && buf[1] == 0x5C && buf[2] == 0x72 && buf[3] == 0x74 && buf[4] == 0x66) {\n        return \"rtf\";\n    }\n\n    if (\n        (buf[0] == 0x77 && buf[1] == 0x4F && buf[2] == 0x46 && buf[3] == 0x46) &&\n        (\n            (buf[4] == 0x00 && buf[5] == 0x01 && buf[6] == 0x00 && buf[7] == 0x00) ||\n            (buf[4] == 0x4F && buf[5] == 0x54 && buf[6] == 0x54 && buf[7] == 0x4F)\n        )\n    ) {\n        return \"woff\";\n    }\n\n    if (\n        (buf[0] == 0x77 && buf[1] == 0x4F && buf[2] == 0x46 && buf[3] == 0x32) &&\n        (\n            (buf[4] == 0x00 && buf[5] == 0x01 && buf[6] == 0x00 && buf[7] == 0x00) ||\n            (buf[4] == 0x4F && buf[5] == 0x54 && buf[6] == 0x54 && buf[7] == 0x4F)\n        )\n    ) {\n        return \"woff2\";\n    }\n\n    if (\n        (buf[34] == 0x4C && buf[35] == 0x50) &&\n        (\n            (buf[8] == 0x00 && buf[9] == 0x00 && buf[10] == 0x01) ||\n            (buf[8] == 0x01 && buf[9] == 0x00 && buf[10] == 0x02) ||\n            (buf[8] == 0x02 && buf[9] == 0x00 && buf[10] == 0x02)\n        )\n    ) {\n        return \"eot\";\n    }\n\n    if (buf[0] == 0x00 && buf[1] == 0x01 && buf[2] == 0x00 && buf[3] == 0x00 && buf[4] == 0x00) {\n        return \"ttf\";\n    }\n\n    if (buf[0] == 0x4F && buf[1] == 0x54 && buf[2] == 0x54 && buf[3] == 0x4F && buf[4] == 0x00) {\n        return \"otf\";\n    }\n\n    if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 && buf[3] == 0x00) {\n        return \"ico\";\n    }\n\n    if (buf[0] == 0x46 && buf[1] == 0x4C && buf[2] == 0x56 && buf[3] == 0x01) {\n        return \"flv\";\n    }\n\n    if (buf[0] == 0x25 && buf[1] == 0x21) {\n        return \"ps\";\n    }\n\n    if (buf[0] == 0xFD && buf[1] == 0x37 && buf[2] == 0x7A && buf[3] == 0x58 && buf[4] == 0x5A && buf[5] == 0x00) {\n        return \"xz\";\n    }\n\n    if (buf[0] == 0x53 && buf[1] == 0x51 && buf[2] == 0x4C && buf[3] == 0x69) {\n        return \"sqlite\";\n    }\n\n    if (buf[0] == 0x4E && buf[1] == 0x45 && buf[2] == 0x53 && buf[3] == 0x1A) {\n        return \"nes\";\n    }\n\n    if (buf[0] == 0x43 && buf[1] == 0x72 && buf[2] == 0x32 && buf[3] == 0x34) {\n        return \"crx\";\n    }\n\n    if (\n        (buf[0] == 0x4D && buf[1] == 0x53 && buf[2] == 0x43 && buf[3] == 0x46) ||\n        (buf[0] == 0x49 && buf[1] == 0x53 && buf[2] == 0x63 && buf[3] == 0x28)\n    ) {\n        return \"cab\";\n    }\n\n    // needs to be before `ar` check\n    if (buf[0] == 0x21 && buf[1] == 0x3C && buf[2] == 0x61 && buf[3] == 0x72 && buf[4] == 0x63 && buf[5] == 0x68 && buf[6] == 0x3E && buf[7] == 0x0A && buf[8] == 0x64 && buf[9] == 0x65 && buf[10] == 0x62 && buf[11] == 0x69 && buf[12] == 0x61 && buf[13] == 0x6E && buf[14] == 0x2D && buf[15] == 0x62 && buf[16] == 0x69 && buf[17] == 0x6E && buf[18] == 0x61 && buf[19] == 0x72 && buf[20] == 0x79) {\n        return \"deb\";\n    }\n\n    if (buf[0] == 0x21 && buf[1] == 0x3C && buf[2] == 0x61 && buf[3] == 0x72 && buf[4] == 0x63 && buf[5] == 0x68 && buf[6] == 0x3E) {\n        return \"ar\";\n    }\n\n    if (buf[0] == 0xED && buf[1] == 0xAB && buf[2] == 0xEE && buf[3] == 0xDB) {\n        return \"rpm\";\n    }\n\n    if (\n        (buf[0] == 0x1F && buf[1] == 0xA0) ||\n        (buf[0] == 0x1F && buf[1] == 0x9D)\n    ) {\n        return \"z\";\n    }\n\n    if (buf[0] == 0x4C && buf[1] == 0x5A && buf[2] == 0x49 && buf[3] == 0x50) {\n        return \"lz\";\n    }\n\n    if (buf[0] == 0xD0 && buf[1] == 0xCF && buf[2] == 0x11 && buf[3] == 0xE0 && buf[4] == 0xA1 && buf[5] == 0xB1 && buf[6] == 0x1A && buf[7] == 0xE1) {\n        return \"msi\";\n    }\n\n    return \"\"; // invalid\n};\n\n/*\n#include <stdio.h>\nint main( int argc, const char **argv ) {\n    if( argc == 2 ) {\n        FILE *fp = fopen( argv[1], \"rb\" );\n        if( fp ) {\n            char buf[512];\n            int len = fread(buf, 1, 512, fp);\n            puts( tinymime(buf, len) );\n            fclose(fp);\n        }\n    }\n}\n*/\n"
  },
  {
    "path": "tinypipe.hpp",
    "content": "// tiny chainable pipes (C++11)\n// - rlyeh, public domain | wtrmrkrlyeh\n\n#pragma once\n#include <vector>\n#include <sstream>\n\ntemplate< typename T, typename istream >\nvoid copy( T &s, const istream &is ) {\n    std::stringstream ss;\n    std::streamsize at = is.rdbuf()->pubseekoff(0,is.cur);\n    ss << is.rdbuf();\n    is.rdbuf()->pubseekpos(at);\n    auto x = ss.str();\n    s.assign( x.begin(), x.end() );\n}\n\ntemplate< typename istream, typename ostream, typename container = std::vector<char> >\nbool pipe( const istream &is, ostream &os, const std::vector< int (*)(const char *, int, char *, int) > &vec = std::vector< int (*)(const char *, int, char *, int) >() ) {\n    container src, dst;\n    container *A = &src, *B = &dst, *C;\n    copy( src, is );\n    if( !is.good() ) {\n        return false;\n    }\n    for( auto &fn : vec ) {\n        auto bounds = fn( (const char *)&(*A)[0],A->size(),0,B->size() );\n        B->resize( bounds );\n        int wlen = fn( (const char *)&(*A)[0], A->size(), &(*B)[0], B->size() );\n        if( wlen >= 0 ) {\n            B->resize( wlen );\n            C = B, B = A, A = C;\n        } else return false;\n    }\n    os.write( &(*A)[0], (*A).size() );\n    return os.good();\n}\n\n\n/*\nint rot13ish( const char *src, int slen, char *dst, int dlen ) {\n    if( !dst ) return slen * 2; // bounds\n    char *bak = dst;\n    const char *p = src, *e = src + slen;\n    while( p < e ) *dst++ = (*p & 0xf0) | (*p & 0x0f) ^ 0x7, ++p;\n    return dst - bak;\n}\nint upper( const char *src, int slen, char *dst, int dlen ) {\n    if( !dst ) return slen * 2; // bounds\n    char *bak = dst;\n    const char *p = src, *e = src + slen;\n    size_t len = e - p;\n    while( p < e ) *dst++ = (*p >= 'a' ? *p - 'a' + 'A' : *p), ++p;\n    return dst - bak;\n}\nint lower( const char *src, int slen, char *dst, int dlen ) {\n    if( !dst ) return slen * 2; // bounds\n    char *bak = dst;\n    const char *p = src, *e = src + slen;\n    size_t len = e - p;\n    while( p < e ) *dst++ = (*p >= 'A' ? *p - 'A' + 'a' : *p), ++p;\n    return dst - bak;\n}\nint noparens( const char *src, int slen, char *dst, int dlen ) {\n    if( !dst ) return slen * 2; // bounds\n    char *bak = dst;\n    const char *p = src, *e = src + slen;\n    while( p < e ) {\n        if( *p != '(' && *p != ')' ) *dst++ = *p++; else *p++;\n    }\n    return dst - bak;\n}\nint numberx2( const char *src, int slen, char *dst, int dlen ) {\n    if( !dst ) return slen * 2; // bounds\n    char *bak = dst;\n    const char *p = src, *e = src + slen;\n    while( p < e ) {\n        bool n = *p >= '0' && *p <= '9';\n        dst[0]=dst[n]=*p++, dst+=n+1;\n    }\n    return dst - bak;\n}\nint l33t( const char *src, int slen, char *dst, int dlen ) {\n    if( !dst ) return slen * 2; // bounds\n    char *bak = dst;\n    const char *p = src, *e = src + slen;\n    while(p < e)\n    switch(*p++) {\n        default: *dst++ = p[-1];\n        break; case 'O': *dst++ = '0';\n        break; case 'T': *dst++ = '7';\n        break; case 'E': *dst++ = '3';\n        break; case 'L': *dst++ = '1';\n        break; case 'I': *dst++ = '1';\n        break; case 'A': *dst++ = '4';\n    }\n    return dst - bak;\n}\n#include <fstream>\n#include <iostream>\n#include <sstream>\nint main() {\n    std::stringstream is; is << \"hello\";\n    pipe( is, std::cout );\n\n    std::ifstream ifs{__FILE__};\n    pipe( ifs, std::cout, { rot13ish, rot13ish } );\n    pipe( ifs, std::cout, { upper, l33t, lower, numberx2, noparens } );\n}\n*/"
  },
  {
    "path": "tinyprint.cc",
    "content": "// Tiny printer. Original code by Evan Wallace. rlyeh, public domain | wtrmrkrlyeh\n#include <iostream>\n\nstruct print {\n\tconst char *sep = \"\";\n\t~print() { std::cout << std::endl; }\n\n\ttemplate<typename T> print& operator,( const T &t ) {\n\t\treturn std::cout << sep << t, sep = \" \", *this;\n\t}\n};\n\n#define print print(),\n\n/*\nint main() {\n   print \"hello\", 123, \"world\";\n   print \"yeah\";\n}\n*/\n"
  },
  {
    "path": "tinypulse.c",
    "content": "// Tiny digital pulses/signals. rlyeh, public domain | wtrmrkrlyeh\n#include <stdio.h>\n\nvoid pulse( int *state ) {\n    switch( state[1] * 2 + state[0] ) {\n        default:\n        break; case 0: puts(\"pulse OFF\");\n        break; case 1: puts(\"pulse UP\");\n        break; case 2: puts(\"pulse DOWN\");\n        break; case 3: puts(\"pulse ON\");\n    }\n    state[1] = state[0];\n}\n\n/*\nint main() {\n    int state[2] = {0};\n\n    *state = 0;\n    pulse(state);\n\n    *state = 1;\n    pulse(state);\n\n    *state = 1;\n    pulse(state);\n\n    *state = 0;\n    pulse(state);\n\n    *state = 0;\n    pulse(state);\n}\n*/\n"
  },
  {
    "path": "tinyroman.cc",
    "content": "// Tiny integer to roman numerals converter (roughly tested). rlyeh, public domain | wtrmrkrlyeh\n#include <map>\n#include <string>\n\nstd::string romanize( int i ) {\n    static std::string table[] = {\n        \"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\", \"VII\", \"VIII\", \"IX\",\n        \"X\", \"XX\", \"XXX\", \"XL\", \"L\", \"LX\", \"LXX\", \"LXXX\", \"XC\",\n        \"C\", \"CC\", \"CCC\", \"CD\", \"D\", \"DC\", \"DCC\", \"DCCC\", \"CM\",\n        \"M\", \"MM\", \"MMM\", \"MMMM\",\n    };\n    std::string out;\n    for( int base = 0; i > 0; base++, i /= 10 ) {\n        int mod = i % 10;\n        if( mod > 0 ) {\n            out = table[(mod - 1) + base * 9] + out;\n        }\n    }\n    return out;\n}\n\n/*\n#include <cassert>\nint main() {\n    assert( romanize(0) == \"\" );\n    assert( romanize(10) == \"X\" );\n    assert( romanize(1990) == \"MCMXC\" );\n    assert( romanize(2008) == \"MMVIII\" );\n    assert( romanize(99) == \"XCIX\" );\n    assert( romanize(47) == \"XLVII\" );\n}\n*/\n"
  },
  {
    "path": "tinystring.c",
    "content": "// C string library\n// - rlyeh, public domain\n\n// temporary strings api (stack)\nchar* strtmp(const char *fmt, ...);\nint stristmp(const char *s);\n\n// allocated strings api (heap)\n#define strnew(fmt, ...) strdup(strtmp(fmt,__VA_ARGS__))\n#define strdel(s)        ((stristmp(s) ? (void)0 : free(s)), (s)=0)\n\n// implementation --------------------------------------------------------------\n\n#if defined _MSC_VER && !defined __thread\n#define __thread __declspec(thread)\n#endif\n\n#include <assert.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n\nint stristmp(const char *s) { // is_va()\n    return (1&(uintptr_t)s) && s[-1] == 0;\n}\nchar* strtmp(const char *fmt, ...) { // va()\n    va_list vl;\n    va_start(vl, fmt);\n    int sz = vsnprintf( 0, 0, fmt, vl ) + 1;\n    va_end(vl);\n\n    int reqlen = sz + 1; // 1 for even padding\n\n    char* ptr;\n    enum { STACK_ALLOC = 16384 };\n    if( reqlen < STACK_ALLOC ) { // fit stack?\n        static __thread char buf[STACK_ALLOC+1];\n        static __thread int cur = 1, len = STACK_ALLOC;\n        ptr = buf + ((cur+reqlen) > len ? cur = 1 : (cur += reqlen) - reqlen);\n    } else { // else use heap (@fixme: single memleak per invoking thread)\n        static __thread char *buf = 0;\n        static __thread int cur = 1, len = -STACK_ALLOC;\n        if( reqlen >= len ) buf = realloc(buf, len = abs(len) * 1.75 + reqlen);\n        ptr = buf + ((cur+reqlen) > len ? cur = 1 : (cur += reqlen) - reqlen);\n    }\n\n    ptr += !(1&(uintptr_t)ptr); // align to even address only when already odd\n    ptr[-1] = 0; // add header\n    assert(stristmp(ptr));\n\n    va_start(vl,fmt);\n    vsnprintf( ptr, sz, fmt, vl );\n    va_end(vl);\n\n    return (char *)ptr;\n}\n\n/*\nint main() {\n    // creation\n    char *x = strtmp(\"hello %d\", 123); puts(x);\n    char *y = strnew(\"hello %d\", 123); puts(y);\n    assert(strcmp(x,y)==0);\n\n    // destruction\n    // strdel(x); assert(x == 0); // optional free, since x is a temporary string (strtmp)\n    strdel(y); assert(y == 0);    // required free, since y was explicitly allocated (with strnew)\n\n    // test concat\n    char *z = strtmp(\"%d\",6); z = strtmp(\"%s%s%s\",z,z,z); assert( 0 == strcmp(z,\"666\") );\n\n    // test memory is never exhausted\n    for(int i = 0; i < 10000; ++i) assert(strtmp(\"hello %d\",123));\n\n    // test asserts are enabled\n    assert(~puts(\"Ok\"));\n}\n*/\n"
  },
  {
    "path": "tinystring.cc",
    "content": "// tiny C++ string utilities\n// - rlyeh, public domain | wtrmrkrlyeh\n\n// @toadd: pad, left, right, center, triml, trimr, trim, [-1]\n\n#include <deque>\n#include <string>\n\nstd::deque< std::string > tokenize( const std::string &self, const char *delimiters ) {\n    char map[256] = {};\n    while( *delimiters++ ) map[ (unsigned char) delimiters[-1] ] = '\\1';\n    std::deque< std::string > tokens(1);\n    for( auto &ch : self ) {\n        /**/ if( !map[(unsigned char)ch] ) tokens.back().push_back( ch );\n        else if( tokens.back().size() ) tokens.push_back( std::string() );\n    }\n    while( tokens.size() && !tokens.back().size() ) tokens.pop_back();\n    return tokens;\n}\n\nstd::deque< std::string > split( const std::string &self, const std::string &delimiters ) {\n    std::string str;\n    std::deque< std::string > tokens;\n    for( auto &ch : self ) {\n        if( delimiters.find_first_of( ch ) != std::string::npos ) {\n            if( str.size() ) tokens.push_back( str ), str = \"\";\n            tokens.push_back( std::string() + ch );\n        } else str += ch;\n    }\n    return str.empty() ? tokens : ( tokens.push_back( str ), tokens );\n}\n\nstd::string left_of( const std::string &substring, const std::string &self ) {\n    std::string::size_type pos = self.find( substring );\n    return pos == std::string::npos ? self : self.substr(0, pos);\n}\n\nstd::string right_of( const std::string &substring, const std::string &self ) {\n    std::string::size_type pos = self.find( substring );\n    return pos == std::string::npos ? self : self.substr(pos + substring.size() );\n}\n\nstd::string replace_one( const std::string &self, const std::string &target, const std::string &replacement ) {\n    std::string str = self;\n    auto found = str.find(target);\n    return found == std::string::npos ? str : (str.replace(found, target.length(), replacement), str);\n}\n\nstd::string replace_all( const std::string &self, const std::string &target, const std::string &replacement ) {\n    size_t found = 0;\n    std::string s = self;\n    while( ( found = s.find( target, found ) ) != std::string::npos ) {\n        s.replace( found, target.length(), replacement );\n        found += replacement.length();\n    }\n    return s;\n}\n\n/*\n#include <assert.h>\nint main() {\n    assert( tokenize(\"a/b/c/\\\\d\\\\e,f,g,\", \"/\\\\,\") == (std::deque<std::string> { \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\" }) );\n    assert( split(\"a/b/c/\\\\d\\\\e,f,g,\", \"/\\\\,\") == (std::deque<std::string> { \"a\", \"/\", \"b\", \"/\", \"c\", \"/\", \"\\\\\", \"d\", \"\\\\\", \"e\", \",\", \"f\", \",\", \"g\", \",\" }) );\n    assert( left_of(\"beginning\", \"in the beginning\") == \"in the \" );\n    assert( right_of(\"in the \", \"in the beginning\") == \"beginning\" );\n    assert( replace_all( \"0cad0\", \"0\", \"abra\" ) == \"abracadabra\" );\n    assert( replace_one( \"0cad0\", \"0\", \"abra\" ) == \"abracad0\" );\n}\n*/\n"
  },
  {
    "path": "tinytga.c",
    "content": "// Tiny TGA writer: original code by jon olick, public domain\n// Elder C version by rlyeh, public domain | wtrmrkrlyeh\n#include <stdio.h>\nstatic void tinytga(FILE *fp, void *rgba, int width, int height, int numChannels) {\n    // Swap RGBA to BGRA if using 3 or more channels\n    int x, i, y, j, bpc = numChannels * 8; // 8 bits per channel\n    int remap[4] = {numChannels >= 3 ? 2 : 0, 1, numChannels >= 3 ? 0 : 2, 3};\n    char *s = (char *)rgba;\n    // Header\n    fwrite(\"\\x00\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\", 12, 1, fp);\n    fwrite(&width, 2, 1, fp);\n    fwrite(&height, 2, 1, fp);\n    fwrite(&bpc, 2, 1, fp);\n    for(y = height-1; y >= 0; --y) {\n        i = (y * width) * numChannels;\n        for(x = i; x < i+width*numChannels; x += numChannels) {\n            for(j = 0; j < numChannels; ++j) {\n                fputc(s[x+remap[j]], fp);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tinytime.cc",
    "content": "// Tiny timing utilities. rlyeh, public domain | wtrmrkrlyeh\n#include <thread>\n#include <chrono>\n#if !defined(TIMING_USE_OMP) && ( defined(USE_OMP) || defined(_MSC_VER) /*|| defined(__ANDROID_API__)*/ )\n#   define TIMING_USE_OMP\n#   include <omp.h>\n#endif\ndouble now() {\n#   ifdef TIMING_USE_OMP\n    static auto const epoch = omp_get_wtime();\n    return omp_get_wtime() - epoch;\n#   else\n    static auto const epoch = std::chrono::steady_clock::now(); // milli ms > micro us > nano ns\n    return std::chrono::duration_cast< std::chrono::microseconds >( std::chrono::steady_clock::now() - epoch ).count() / 1000000.0;\n#   endif\n}\ndouble bench( void (*fn)() ) {\n    double took = -now();\n    return ( fn(), took + now() );\n}\nvoid sleep( double secs ) {\n    std::chrono::microseconds duration( (int)(secs * 1000000) );\n    std::this_thread::sleep_for( duration );\n}\n\n/*\n#include <stdio.h>\nint main() {\n    double t0 = now();\n    printf(\"%g s.\\n\", bench( []{ sleep(0.1234); } ) );\n    double t1 = now();\n    printf(\"%g s.\\n\", t1 - t0 );\n}\n*/\n"
  },
  {
    "path": "tinytodo.c",
    "content": "// Tiny todo() static assert macro. based on code by https://github.com/andyw8/do_by\n// - rlyeh, public domain | wtrmrkrlyeh\n\n#pragma once\n#include <stdio.h>\n\nstatic inline int TODO(const char *DT) { return\n       /*D*/ ( DT[4] == ' ' ? 0 : (DT[4] - '0') * 10 ) + (DT[5] - '0') +\n       /*M*/ ( DT[2] == 'n' ? 1\n             : DT[2] == 'b' ? 2\n             : DT[2] == 'r' && DT[0] == 'M' ? 3\n             : DT[2] == 'r' && DT[0] != 'M' ? 4\n             : DT[2] == 'y' ? 5\n             : DT[2] == 'n' ? 6\n             : DT[2] == 'l' ? 7\n             : DT[2] == 'g' ? 8\n             : DT[2] == 'p' ? 9\n             : DT[2] == 't' ? 10\n             : DT[2] == 'v' ? 11 : 12 ) * 100 +\n       /*Y*/ (DT[7] - '0') * 1e7 + (DT[8] - '0') * 1e6 + (DT[9] - '0') * 1e5 + (DT[10] - '0') * 1e4;\n}\n\n#define TODO(DT) do { static int ever = 0; if(!ever) { ever = 1; if( TODO(__DATE__) >= TODO(DT) ) fprintf(stderr, \"TODO date expired! %s\\n\", DT); } } while(0)\n\n/*\nint main() {\n    TODO( \"Aug 11 2011: Finish prototype. Warn if current date >= Aug 11 2011\" );\n    TODO( \"May 19 2014: Finish gameplay. Warn if current date >= May 19 2014\" );\n    TODO( \"Sep 26 2015: Finish QA. Warn if current date >= Sep 26 2015\" );\n}\n*/\n"
  },
  {
    "path": "tinytty.c",
    "content": "// Tiny terminal utilities. rlyeh, public domain | wtrmrkrlyeh\n#include <stdio.h>\n\n#ifdef _WIN32\n#define ANSI(ansi, win) win\n#else\n#define ANSI(ansi, win) ansi\n#endif\n\n// A few unicode characters and ANSI colors\nstatic const char *tick   = ANSI(\"\\u2713\", \"[v]\"), *cross   = ANSI(\"\\u2717\", \"[x]\"), *arrow = ANSI(\"\\u2794\", \"[>]\");\nstatic const char *red    = ANSI(\"\\27[31m\",\"\"),    *green   = ANSI(\"\\27[32m\",\"\"),    *blue = ANSI(\"\\27[34m\",\"\");\nstatic const char *yellow = ANSI(\"\\27[33m\",\"\"),    *magenta = ANSI(\"\\27[35m\",\"\"),    *cyan = ANSI(\"\\27[36m\",\"\");\nstatic const char *end    = ANSI(\"\\27[0m\",\"\");\n\n// 256-color terminal\nvoid tty256( unsigned char r, unsigned char g, unsigned char b ) {\n    ANSI(printf(\"\\033[38;5;%dm\", (r/51)*36+(g/51)*6+(b/51)+16), (void)0);\n}\n\n// terminal writer w/ console width clamping\n#ifdef _WIN32\n#include <string.h>\n#include <winsock2.h>\n#endif\nvoid tty( const char *txt ) {\n#ifdef _WIN32\n    CONSOLE_SCREEN_BUFFER_INFO c;\n    if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &c) ) {\n        int len = strlen(txt), w = c.srWindow.Right-c.srWindow.Left-c.dwCursorPosition.X;\n        printf(\"%.*s%s\\n\", len > w ? w - 3 : w, txt, len > w ? \"...\" : \"\" );\n        return;\n    }\n#endif\n    puts( txt );\n}\n\n/*\nint main() {\n    // usage:\n    printf(\"%s%s%s%s%s\\n\", green, tick, yellow, \" passed\", end);\n    // or:\n    tty256( 255, 192, 0 );\n    printf(\"%s\\n\", \"256 colors\");\n    // also:\n    tty( \"DECREASE WINDOW WIDTH AND RUN THE APP AGAIN! DECREASE WINDOW WIDTH AND RUN THE APP AGAIN! DECREASE WINDOW WIDTH AND RUN THE APP AGAIN! DECREASE WINDOW WIDTH AND RUN THE APP AGAIN! \" );\n    // // more tests:\n    // tty( \"hey\" );\n    // printf(\"%s\", \"[test] \");\n    // tty( \"DECREASE WINDOW WIDTH AND RUN THE APP AGAIN! DECREASE WINDOW WIDTH AND RUN THE APP AGAIN! DECREASE WINDOW WIDTH AND RUN THE APP AGAIN! DECREASE WINDOW WIDTH AND RUN THE APP AGAIN! \" );\n}\n*/\n"
  },
  {
    "path": "tinyuniso.cc",
    "content": "// tiny iso/9660 unarchiver. [ref] http://wiki.osdev.org/ISO_9660\n// - rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <functional>\n#include <stdint.h>\n#include <string>\n#include <vector>\n\ntemplate<typename FN, typename istream>\nbool tinyuniso( istream &is, const FN &yield ) {\n    // directory record\n    struct dir_t {\n        uint8_t  flags;\n        uint64_t offset;\n        uint64_t length;\n        uint16_t parent;\n        union { uint8_t st[7]; struct { uint8_t Y,M,D,h,m,s,GMT; }; };\n        std::string name;\n    } root = {}; \n\n    // unpack data (raw)\n    auto unpack_raw = [&]( int l, void *ptr ) {\n        if( !ptr ) is.ignore( l ); else is.read( (char *)ptr, l );\n    };\n\n    // unpack directory record\n    auto unpack_record = [&]( dir_t *out ) -> uint8_t {\n        auto get_max_of = []( int a, int b ) { return a < b ? b : a; };\n        auto unpack_16L = [&]( uint32_t *t ) { unpack_raw(4, t); if(t) *t &= (uint16_t)(-1); };\n        auto unpack_32L = [&]( uint64_t *t ) { unpack_raw(8, t); if(t) *t &= (uint32_t)(-1); };\n        auto unpack_str = [&]( int l, std::string *s ) {\n            s->resize( l );\n            unpack_raw( l, &(*s)[0] );\n            while( !s->empty() && s->back() == ' ' ) s->pop_back();     // rstrip(' ')\n            *s = s->substr( 0, s->find_first_of(';') );                 // left_of(';')\n            for( auto &ch : *s ) ch -= 32 * ( ch >= 'a' && ch <= 'z' ); // upper()\n        };\n        uint8_t len0, len1;\n        unpack_raw( 1, &len0 );\n        if( len0 ) {\n            unpack_raw( 1, 0 );\n            unpack_32L( &(out->offset) );\n            unpack_32L( &(out->length) );\n            unpack_raw( 7, &(out->st) );\n            unpack_raw( 1, &(out->flags) );\n            unpack_raw( 1+1+4, 0 );\n            unpack_raw( 1, &len1 );\n            unpack_str( len1, &(out->name) );\n            unpack_raw( !(len1 % 2), 0);\n            unpack_raw( get_max_of(0, len0 - (34 + len1 - (len1 % 2))), 0 );\n        } else len0 = 1, *out = dir_t();\n        return len0;\n    };\n\n    // retrieve partial contents\n    auto get_sector = [&]( int64_t sector, int64_t length ) {\n        return is.seekg( sector*2048, is.beg ), is.good();\n    };\n\n    // retrieve whole file contents\n    auto get_file = [&]( char *ptr, const dir_t &f ) {\n        get_sector( f.offset, f.length );\n        unpack_raw( f.length, ptr );\n    };\n\n    // parse volume descriptors\n    int sector = 0x10;\n    while( get_sector(sector++, 2048) ) {\n        uint8_t typecode;\n        unpack_raw(1, &typecode);\n\n        /**/ if( typecode == 255 ) break;\n        else if( typecode == 0x1 ) { // skip most of primary volume descriptor\n            std::string id(5, '\\0');\n            unpack_raw(5, &id[0]); if(id != \"CD001\") return false;\n            unpack_raw(1+1+32+32+8+8+32+4+4+4+8+4+4+4+4, 0);\n            unpack_record( &root ); break;\n        }\n        else return false;\n    }\n\n    // recurse directory structure\n    using fn = std::function<void (const dir_t &, const char *)>;\n    fn tree = [&] ( const dir_t &node, const char *parent ) {\n        std::vector<dir_t> list;\n        // unpack dir\n        auto sector = node.offset;\n        auto read = 0;\n        get_sector(sector, 2048);\n        dir_t self; read += unpack_record( &self );\n        dir_t prev; read += unpack_record( &prev );\n        // iterate children\n        while( read < self.length ) {\n            if( read % 2048 == 0) {\n                get_sector(++sector, 2048);\n            }\n\n            dir_t data;\n            read += unpack_record( &data );\n\n            if( data.name.empty() ) { // if end of directory\n                auto skip = 2048 - (read % 2048);\n                unpack_raw(skip, 0);\n                read += skip;\n            } else {\n                list.push_back( data );\n            }\n        }\n        // iterate listing: recurse if dir, else yield file\n        for( auto &c : list ) {\n            if( c.flags & 2 ) {\n                tree( c, (node.name + \"/\").c_str() );\n            } else {\n                std::string fname = std::string(\"/\") + parent + node.name + \"/\" + c.name;\n                char buffer[128] = {};\n                auto offset = (int)(c.GMT) * 15 * 60; // offset in seconds from GMT in 15min intervals\n                sprintf(buffer, \"%d/%02d/%02d %02d:%02d:%02d%c%d\", 1900+c.Y, c.M, c.D, c.h, c.m, c.s, offset >= 0 ? '+':'-', offset );\n                if( char *ptr = yield( fname, c.length, buffer, c.offset ) ) {\n                    get_file( ptr, c );\n                }\n            }\n        }\n    };\n\n    tree(root, \"\");\n    return is.good();\n}\n\n/*\n#include <iostream>\n#include <fstream>\nint main( int argc, const char **argv ) {\n    if( argc <= 1 ) {\n        return std::cout << \"Usage: \" << argv[0] << \" file.iso [path]\" << std::endl, -1;\n    }\n    std::string read;\n    std::ifstream ifs( argv[1], std::ios::binary );\n    bool ok = ifs.good() && tinyuniso( ifs, \n        [&]( const std::string &path, uint64_t size, const char *stamp, uint64_t offset ) { \n            // .csv list\n            std::cout << \"'\" << path << \"',\" << size << \",'\" << stamp  << \"'\" << std::endl;\n            // read file (if provided)\n            if( argc > 2 && path == argv[2] ) {\n                read.resize( size );\n                return &read[0];\n            }\n            return (char *)0;\n        }\n    );\n    if( !read.empty() ) std::cout << read << std::endl;\n    return ok;\n}\n*/\n"
  },
  {
    "path": "tinyunit.c",
    "content": "// Tiny unittest suite. rlyeh, public domain | wtrmrkrlyeh\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#define suite(...) if(printf(\"------ \" __VA_ARGS__),puts(\"\"),1)\n#define test(...)  (errno=0,++tst,err+=!(ok=!!(__VA_ARGS__))),printf(\"[%s] L%d %s (%s)\\n\",ok?\" OK \":\"FAIL\",__LINE__,#__VA_ARGS__,strerror(errno))\nstatic unsigned tst=0,err=0,ok=1; static void summary(void){ suite(\"summary\"){ printf(\"[%s] %d tests = %d passed + %d errors\\n\",err?\"FAIL\":\" OK \",tst,tst-err,err); }; }\n\n/*\nint main() {\n    atexit( summary );\n    // orphan test\n    test(1<2);\n    // grouped tests\n    suite(\"grouped tests %d/%d\", 1,1) {\n        test(1<2);\n        test(1<2);\n    }\n    suite(\"grouped tests %d/%d\", 1,2) {\n        test(1<2);\n        test(1<2);\n    }\n}\n*/"
  },
  {
    "path": "tinyuntar.cc",
    "content": "// portable gnu tar and ustar extraction\n// - rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <string>\n#include <stdint.h>\n\ntemplate<typename FN, typename istream>\nbool tinyuntar( istream &is, const FN &yield ) {\n    enum {\n        name     =   0, // (null terminated)\n        mode     = 100, // (octal)\n        uid      = 108, // (octal)\n        gid      = 116, // (octal)\n        size     = 124, // (octal)\n        modtime  = 136, // (octal)\n        checksum = 148, // (octal)\n        type     = 156, // \\0|'0':file,1:hardlink,2:symlink,3:chardev,4:blockdev,5:dir,6:fifo,L:longnameblocknext\n        linkname = 157, // if !ustar link indicator\n        magic    = 257, // if ustar \"ustar\" -- 6th character may be space or null, else zero\n        version  = 263, // if ustar \"00\", else zero\n        uname    = 265, // if ustar owner username, else zero\n        gname    = 297, // if ustar owner groupname, else zero\n        devmajor = 329, // if ustar device major number, else zero\n        devminor = 337, // if ustar device minor number , else zero\n        path     = 345, // if ustar filename prefix, else zero\n        padding  = 500, // if ustar relevant for checksum, else zero\n        total    = 512\n    };\n\n    // equivalent to sscanf(buf, 8, \"%.7o\", &size); or (12, \"%.11o\", &modtime)\n    // ignores everything after first null or space, including trailing bytes\n    struct octal { \n        uint64_t operator()( const char *src, const char *eof ) const {\n            uint64_t sum = 0, mul = 1;\n            const char *ptr = eof;\n            while( ptr-- >= src ) eof  = ( 0 != ptr[1] && 32 != ptr[1] ) ? eof : ptr;\n            while( eof-- >= src ) sum += (uint8_t)(eof[1] - '0') * mul, mul *= 8;\n            return sum;\n    } };\n\n    // handle both regular tar and ustar tar filenames until end of tar is found\n    for( char header[512], blank[512] = {}; is.good(); ) {\n        is.read( header, 512 );\n        if( memcmp( header, blank, 512 ) ) {                                      // if not end of tar\n            if( !memcmp( header+magic, \"ustar\", 5 ) ) {                           // if valid ustar\n                int namelen = strlen(header+name), pathlen = strlen(header+path); // read filename\n                std::string entry =\n                std::string(header+path, pathlen < 155 ? pathlen : 155 ) + (pathlen ? \"/\" : \"\") +\n                std::string(header+name, namelen < 100 ? namelen : 100 );\n\n                switch( header[type] ) {\n                    default:                                                      // unsupported file type\n                    break; case '5': //yield(entry.back()!='/'?entry+'/':entry,0);// directory\n                    break; case 'L': entry = header+name; is.read( header, 512 ); // gnu tar long filename\n                    break; case '0': case 0: {                                    // regular file\n                        uint64_t len = octal()(header+size, header+modtime);      // decode octal size\n                        char *dst = (len ? yield(entry, len) : 0);                // read block if processed\n                        if( dst ) is.read( dst, len ); else is.ignore( len );     // skip block if unprocessed\n                        is.ignore( (512 - (len & 511)) & 511 );                   // skip padding\n                    }\n                }\n            } else return false;\n        } else return is.good();\n    }\n\n    return false;\n}\n\n/*\n#include <iostream>\n#include <fstream>\n#include <map>\nint main( int argc, const char **argv ) {\n    if( argc != 2 ) return std::cerr << \"Usage: \" << argv[0] << \" archive.tar\" << std::endl, -1;\n    std::map<std::string, char *> dir;\n    std::ifstream in(argv[1], std::ios_base::binary);\n    return tinyuntar( in, [&]( const std::string &filename, uint64_t size ) {\n        std::cout << filename << \" (\" << size << \" bytes)\" << std::endl;\n        return dir[ filename ] = (char *)malloc( size ); // processed if valid ptr, skipped if null\n    } );\n}\n*/\n"
  },
  {
    "path": "tinyunzip.cc",
    "content": "// tiny zip unarchiver. based on junzip by Joonas Pihlajamaa\n// - rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <stdint.h>\n#include <vector>\n\n#define STBI_NO_WRITE\n#define STBI_NO_HDR\n#define STB_IMAGE_IMPLEMENTATION\n#define STB_IMAGE_STATIC\n#include \"stb_image.h\"\n\ntemplate<typename FN, typename istream>\nbool tinyunzip( istream &is, const FN &yield ) {\n    bool swaple = 0;\n    auto swap16 = [&]( uint16_t t ) { return !swaple ? t : (t >>  8) | (t <<  8); };\n    auto swap32 = [&]( uint32_t t ) { return !swaple ? t : (t >> 24) | (t << 24) | ((t >> 8) & 0xff00) | ((t & 0xff00) << 8); };\n\n#pragma pack( push, 1 )\n    struct global_file_header {\n        uint32_t magic; // <--\n        uint16_t version;\n        uint16_t versionreq;\n        uint16_t flags;\n        uint16_t zmethod; // <--\n        uint16_t modftme;\n        uint16_t modfdte;\n        uint32_t crc32;\n        uint32_t size;\n        uint32_t unsize;\n        uint16_t namelen; // <-- filename length\n        uint16_t xtralen; // <-- extra field length\n        uint16_t commlen; // <-- comment filed length\n        uint16_t beginvol;\n        uint16_t attrint;\n        uint32_t attrext;\n        uint32_t offsrel; // <--\n    } gfh = {};\n\n    struct file_header {\n        uint16_t zmethod; // <--\n        uint16_t modftme;\n        uint16_t modfdte;\n        uint32_t crc32;\n        uint32_t size;   // <--\n        uint32_t unsize; // <--\n        union  { uint32_t offset;  // <--\n        struct { uint16_t namelen; // <--\n                 uint16_t xtralen; // <--\n        }; };\n    } fh = {};\n\n    struct local_file_header {\n        uint32_t magic; // <--\n        uint16_t versionreq;\n        uint16_t flags;\n        file_header fh;\n    } lfh;\n\n    struct end_record {\n        uint32_t magic; // <-- 0x06054b50\n        uint16_t volno; // <--\n        uint16_t volnodir; // <--\n        uint16_t volentries; // <--\n        uint16_t totentries; // <--\n        uint32_t dirsize;\n        uint32_t diroffs; // <--\n        uint16_t commlen; // after this field, zip file comment follows (variable size)\n    } er = {};\n#pragma pack( pop )\n\n    enum { BUFFER_SIZE = 65536 }; // max name len\n    std::vector<char> buffer( BUFFER_SIZE ), cdata;\n\n    auto read_end_record = [&] {\n        is.seekg( 0, is.end );\n        size_t total = is.tellg();\n        if( total >= sizeof(end_record) ) {\n            size_t to_read = (total < BUFFER_SIZE) ? total : BUFFER_SIZE;\n            is.seekg( total - to_read, is.beg );\n            is.read( &buffer[0], to_read );\n            for( int at = to_read - sizeof(end_record); at >= 0; at-- ) {\n                er = *(end_record *) &buffer[at];\n                if( er.magic == 0x06054B50 || er.magic == 0x504B5460 ) {\n                    swaple = er.magic != 0x06054B50;\n                    return !swap16(er.volno) && !swap16(er.volnodir) && swap16(er.totentries) == swap16(er.volentries);\n                }\n            }\n        }\n        return false;\n    };\n\n    auto read_central_dir = [&] {\n        is.seekg( swap32(er.diroffs), is.beg );\n        if( is.good() ) for( int it = 0; it < swap16(er.totentries); it++ ) {\n            is.read( (char *)&gfh, sizeof(global_file_header) );\n            if( is.good() && gfh.magic == swap32(0x02014B50) && swap16(gfh.namelen) + 1 < BUFFER_SIZE ) {\n                is.read( (char *)&buffer[0], swap16(gfh.namelen) );\n                buffer[ swap16(gfh.namelen) ] = '\\0';\n                is.seekg( swap16(gfh.xtralen) + swap16(gfh.commlen), is.cur );\n                fh = *(file_header *)&gfh.zmethod;\n                fh.offset = gfh.offsrel;\n                if( swap32(fh.size) != 0 || buffer[ swap16(gfh.namelen) - 1 ] != '/' )   // if not dir\n                if( swap16(fh.zmethod) == 0 || swap16(fh.zmethod) == 8 ) {               // if supported\n                    char *ptr = yield( &buffer[0], swap32(fh.unsize), swap32(fh.size) ); // reserve\n                    if( ptr ) {\n                        auto pos = is.tellg();\n                        is.seekg( swap32(fh.offset), is.beg );\n                        is.read( (char *)&lfh, sizeof(local_file_header) );\n                        if( lfh.magic != swap32(0x04034B50) ) return false;\n                        is.seekg(swap16(lfh.fh.namelen) + swap16(lfh.fh.xtralen), is.cur);\n                        if( swap16(fh.zmethod) ) {\n                            cdata.resize( swap32(fh.size) );\n                            is.read( &cdata[0], cdata.size() );\n                            if( stbi_zlib_decode_noheader_buffer( ptr, swap32(fh.unsize), &cdata[0], swap32(fh.size) ) < 0 ) {\n                                return false;\n                            }\n                        } else {\n                            is.read( ptr, swap32(fh.size) );\n                        }\n                        is.seekg( pos, is.beg );\n                    }\n                }\n            } else return false;\n        } else return false;\n        return true;\n    };\n\n    return read_end_record() && read_central_dir() && is.good();\n}\n\n/*\n#include <fstream>\n#include <iostream>\n#include <map>\nint main( int argc, const char **argv ) {\n    std::map<std::string, char *> toc;\n    std::ifstream is( argc > 1 ? argv[1] : argv[0], std::ios::binary );\n    return tinyunzip( is, [&]( const char *filename, int dlen, int zlen ) {\n        std::cout << filename << \" \" << zlen << \" -> \" << dlen << std::endl;\n        return toc[ filename ] = (char *)malloc(dlen);\n    } );\n}\n*/\n"
  },
  {
    "path": "tinyvariant.cc",
    "content": "// Tiny variant class. rlyeh, public domain | wtrmrkrlyeh\n#include <string>\n#include <functional>\n\nstruct var {\n    int type;\n    union {\n        int integer;\n        double real;\n        std::string *string;\n        std::function<void()> *callback;\n    };\n\n    var() : type(0), integer(0)\n    {}\n\n    var( const int &i ) : type(0), integer(i)\n    {}\n\n    var( const double &r ) : type(1), real(r)\n    {}\n\n    var( const std::string &r ) : type(2), string( new std::string(r) )\n    {}\n\n    template<unsigned N>\n    var( const char (&s)[N]) : type(2), string( new std::string(s) )\n    {}\n\n    template<typename T>\n    var( const T &fn ) : type(3), callback( new std::function<void()>(fn) )\n    {}\n\n    var( const var &other ) {\n        operator=( other );\n    }\n\n    ~var() {\n        cleanup();\n    }\n\n    void cleanup() {\n        /**/ if( type == 3 ) delete callback, callback = 0;\n        else if( type == 2 ) delete string, string = 0;\n        type = 0;\n    }\n\n    var &operator=( const var &other ) {\n        if( &other != this ) {\n            cleanup();\n            type = other.type;\n            /**/ if( type == 0 ) integer = other.integer;\n            else if( type == 1 ) real = other.real;\n            else if( type == 2 ) string = new std::string( *other.string );\n            else if( type == 3 ) callback = new std::function<void()>( *other.callback );\n        }\n        return *this;\n    }\n\n    void operator()() const {\n        if( type == 3 ) if( *callback ) (*callback)();\n    }\n\n    template<typename ostream>\n    inline friend ostream &operator <<( ostream &os, const var &self ) {\n        /**/ if( self.type == 0 ) return os << self.integer, os;\n        else if( self.type == 1 ) return os << self.real, os;\n        else if( self.type == 2 ) return os << *self.string, os;\n        else if( self.type == 3 ) return os << '[' << self.callback << ']', os;\n        return os;\n    }\n};\n\ntemplate<typename T> inline bool is(const var &v) { return false; }\ntemplate<>           inline bool is<int>(const var &v) { return v.type == 0; }\ntemplate<>           inline bool is<double>(const var &v) { return v.type == 1; }\ntemplate<>           inline bool is<std::string>(const var &v) { return v.type == 2; }\ntemplate<>           inline bool is<std::function<void()>>(const var &v) { return v.type == 3; }\n\ntemplate<typename T> inline const T& cast(const var &v) { static T t; return t = T(); }\ntemplate<>           inline const int& cast<int>(const var &v) { return v.integer; }\ntemplate<>           inline const double& cast<double>(const var &v) { return v.real; }\ntemplate<>           inline const std::string& cast<std::string>(const var &v) { return *v.string; }\ntemplate<>           inline const std::function<void()>& cast<std::function<void()>>(const var &v) { return *v.callback; }\n\n/*\n#include <iostream>\n#include <assert.h>\nint main() {\n    std::cout << \"sizeof(var)=\" << sizeof(var) << std::endl;\n\n    var digit = 42, other = \"hello world\";\n\n    std::cout << digit << std::endl; assert( is<int>(digit) );\n    std::cout << other << std::endl; assert( is<std::string>(other) );\n\n    other = digit;\n    std::cout << other << std::endl; assert( is<int>(other) );\n\n    other = []{ std::cout << \"callback!\" << std::endl; };\n    std::cout << other << std::endl;\n    other();\n}\n*/\n"
  },
  {
    "path": "tinyvbyte.h",
    "content": "// tiny variable byte length encoder/decoder (vbyte)\n// - rlyeh, public domain | wtrmrkrlyeh\n#pragma once\n#include <stdint.h>\n\nenum { VBYTE_MIN_REQ_BYTES = 1, VBYTE_MAX_REQ_BYTES = 10 };\n\nstatic uint64_t vbuencode( uint8_t *buffer, uint64_t value ) {\n    /* 7-bit packing. MSB terminates stream */\n    const uint8_t *buffer0 = buffer;\n    do {\n        *buffer++ = (uint8_t)( 0x80 | (value & 0x7f) );\n        value >>= 7;\n    } while( value > 0 );\n    *(buffer-1) ^= 0x80;\n    return buffer - buffer0;\n}\nstatic uint64_t vbudecode( uint64_t *value, const uint8_t *buffer ) {\n    /* 7-bit unpacking. MSB terminates stream */\n    const uint8_t *buffer0 = buffer;\n    uint64_t out = 0, j = -7;\n    do {\n        out |= (( ((uint64_t)(*buffer)) & 0x7f) << (j += 7) );\n    } while( ((uint64_t)(*buffer++)) & 0x80 );\n    *value = out;\n    return buffer - buffer0;\n}\n\nstatic uint64_t vbiencode( uint8_t *buffer, int64_t value ) {\n    /* convert sign|magnitude to magnitude|sign */\n    uint64_t nv = (uint64_t)((value >> 63) ^ (value << 1));\n    /* encode unsigned */\n    return vbuencode( buffer, nv );\n}\nstatic uint64_t vbidecode( int64_t *value, const uint8_t *buffer ) {\n    /* decode unsigned */\n    uint64_t nv, ret = vbudecode( &nv, buffer );\n    /* convert magnitude|sign to sign|magnitude */\n    *value = ((nv >> 1) ^ -(nv & 1));\n    return ret;\n}\n\n/*\n#include <stdio.h>\n#define test(type, encfunc, decfunc, number) do { \\\n    type copy; \\\n    char buf[16]; \\\n    int written = encfunc( buf, number ), i = 0; \\\n    printf(\"[    ] %s: \", #type); \\\n    while( i < written ) printf(\"%02x,\", (uint8_t)buf[i++] ); \\\n    decfunc( &copy, buf ); \\\n    printf(\"\\r%s\\n\", copy == number ? \"[ OK ]\" : \"[FAIL]\"); \\\n} while(0)\nint main() {\n    test( int64_t, vbiencode, vbidecode,  0);\n    test( int64_t, vbiencode, vbidecode, -1);\n    test( int64_t, vbiencode, vbidecode, +1);\n    test( int64_t, vbiencode, vbidecode, -2);\n    test( int64_t, vbiencode, vbidecode, +2);\n    test( int64_t, vbiencode, vbidecode, INT8_MIN);\n    test( int64_t, vbiencode, vbidecode, INT8_MAX);\n    test( int64_t, vbiencode, vbidecode, INT16_MIN);\n    test( int64_t, vbiencode, vbidecode, INT16_MAX);\n    test( int64_t, vbiencode, vbidecode, INT32_MIN);\n    test( int64_t, vbiencode, vbidecode, INT32_MAX);\n    test( int64_t, vbiencode, vbidecode, INT64_MIN);\n    test( int64_t, vbiencode, vbidecode, INT64_MAX);\n\n    test(uint64_t, vbuencode, vbudecode, 0);\n    test(uint64_t, vbuencode, vbudecode, 1);\n    test(uint64_t, vbuencode, vbudecode, 2);\n    test(uint64_t, vbuencode, vbudecode, 3);\n    test(uint64_t, vbuencode, vbudecode, 4);\n    test(uint64_t, vbuencode, vbudecode, UINT8_MAX);\n    test(uint64_t, vbuencode, vbudecode, UINT16_MAX);\n    test(uint64_t, vbuencode, vbudecode, UINT32_MAX);\n    test(uint64_t, vbuencode, vbudecode, UINT64_MAX);\n}\n*/\n"
  },
  {
    "path": "tinywav.c",
    "content": "// Tiny WAV writer: original code by jon olick, public domain\n// Floating point support + pure C version by rlyeh, public domain | wtrmrkrlyeh\n#include <stdio.h>\nstatic void tinywav(FILE *fp, short numChannels, short bitsPerSample, int sampleRateHz, const void *data, int size, int is_floating) {\n    short bpsamp;\n    int length, bpsec;\n    fwrite(\"RIFF\", 1, 4, fp);\n    length = size + 44 - 8;\n    fwrite(&length, 1, 4, fp);\n    fwrite(is_floating ? \"WAVEfmt \\x10\\x00\\x00\\x00\\x03\\x00\" : \"WAVEfmt \\x10\\x00\\x00\\x00\\x01\\x00\", 1, 14, fp);\n    fwrite(&numChannels, 1, 2, fp);\n    fwrite(&sampleRateHz, 1, 4, fp);\n    bpsec = numChannels * sampleRateHz * bitsPerSample/8;\n    fwrite(&bpsec, 1, 4, fp);\n    bpsamp = numChannels * bitsPerSample/8;\n    fwrite(&bpsamp, 1, 2, fp);\n    fwrite(&bitsPerSample, 1, 2, fp);\n    fwrite(\"data\", 1, 4, fp);\n    fwrite(&size, 1, 4, fp);\n    fwrite(data, 1, size, fp);\n}\n"
  },
  {
    "path": "tinywtf.h",
    "content": "// tiny portable host macros (C/C++ language features, compilers, os, arch, tls...)\n// used to avoid #if/n/def hell.\n// - rlyeh, public domain | wtrmrkrlyeh\n\n#ifndef $no\n\n// Core\n\n#define $no(...)\n#define $yes(...)        __VA_ARGS__\n\n// Directive modifiers\n\n#define $on(v)          (0 v(+1))  // usage: #if $on($cl)\n#define $is             (0 v(+1))  // usage: #if $is($debug)\n#define $has(...)       $clang(__has_feature(__VA_ARGS__)) $nclang(__VA_ARGS__) // usage: #if $has(cxx_exceptions)\n\n// Text/code modifiers\n\n#define $quote(...)     #__VA_ARGS__\n#define $comment        $no\n#define $uncomment      $yes\n\n// Compiler utils\n\n#include <stdint.h>\n#if   INTPTR_MAX == INT64_MAX\n#   define $bits64    $yes\n#   define $bits32    $no\n#elif INTPTR_MAX == INT32_MAX\n#   define $bits64    $no\n#   define $bits32    $yes\n#else\n#   define $bits64    $no\n#   define $bits32    $no\n#endif\n\n#if defined(NDEBUG) || defined(_NDEBUG) || defined(RELEASE)\n#   define $release   $yes\n#   define $debug     $no\n#else\n#   define $release   $no\n#   define $debug     $yes\n#endif\n\n#if defined(NDEVEL) || defined(_NDEVEL) || defined(PUBLIC)\n#   define $public    $yes\n#   define $devel     $no\n#else\n#   define $public    $no\n#   define $devel     $yes\n#endif\n\n#if defined(__GNUC__) || defined(__MINGW32__)\n#   define $gcc       $yes\n#   define $ngcc      $no\n#else\n#   define $gcc       $no\n#   define $ngcc      $yes\n#endif\n\n#ifdef _MSC_VER\n#   define $cl        $yes\n#   define $ncl       $no\n#else\n#   define $cl        $no\n#   define $ncl       $yes\n#endif\n\n#ifdef __clang__\n#   define $clang     $yes\n#   define $nclang    $no\n#else\n#   define $clang     $no\n#   define $nclang    $yes\n#endif\n\n#if $on($cl) || $on($gcc) || $on($clang)\n#   define $supported_compiler   $yes\n#   define $unsupported_compiler $no\n#else\n#   define $supported_compiler   $no\n#   define $unsupported_compiler $yes\n#endif\n\n// usage: if $likely (expr) { ... }\n\n#if $on($gcc) || $on($clang)\n#   define $likely(expr)    (__builtin_expect(!!(expr), 1))\n#   define $unlikely(expr)  (__builtin_expect(!!(expr), 0))\n#else\n#   define $likely(expr)    ((expr))\n#   define $unlikely(expr)  ((expr))\n#endif\n\n// create a $warning(...) macro\n// usage: $warning(\"this is shown at compile time\")\n\n#if   $on($gcc) || $on($clang)\n#   define $w4rning(msg) _Pragma(#msg)\n#   define $warning(msg) $w4rning( message( msg ) )\n#elif $on($cl)\n#   define $warning(msg) __pragma( message( msg ) )\n#else\n#   define $warning(msg)\n#endif\n\n// create a $todo(...) macro\n// usage: $todo(\"this is shown at compile time\")\n\n#define $t0d0(X)   #X\n#define $tod0(X)   $t0d0(X)\n#define $todo(...) $warning( __FILE__ \"(\" $tod0(__LINE__)\") : $todo - \" #__VA_ARGS__ \" - [ \" $cl(__FUNCTION__) $ncl(__func__) \" ]\" )\n\n// C++ detect and version\n\n#ifdef __cplusplus\n#   define $c              $no\n#   define $cpp            $yes\n#   if (__cplusplus < 201103L && !defined(_MSC_VER)) || (defined(_MSC_VER) && (_MSC_VER < 1700)) || (defined(__GLIBCXX__) && __GLIBCXX__ < 20130322L)\n#      define $cpp11       $no\n#      define $cpp03       $yes\n#   else\n#      define $cpp11       $yes\n#      define $cpp03       $no\n#   endif\n#else\n#   define $c              $yes\n#   define $cpp            $no\n#   define $cpp11          $no\n#   define $cpp03          $no\n#endif\n\n// C++ exceptions\n\n#if defined(__cplusplus) && ( \\\n    (defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS > 0)) || \\\n    (defined(_STLP_USE_EXCEPTIONS) && (_STLP_USE_EXCEPTIONS > 0)) || \\\n    (defined(HAVE_EXCEPTIONS)) || \\\n    (defined(__EXCEPTIONS)) || \\\n    (defined(_CPPUNWIND)) || \\\n    ($has(cxx_exceptions)) ) /*(__has_feature(cxx_exceptions))*/\n#   define $exceptions    $yes\n#   define $nexceptions   $no\n#else\n#   define $exceptions    $no\n#   define $nexceptions   $yes\n#endif\n\n// Thread Local Storage\n\n#if defined(__MINGW32__) || defined(__SUNPRO_C) || defined(__xlc__) || defined(__GNUC__) || defined(__clang__) || defined(__GNUC__) // __INTEL_COMPILER on linux\n//   MingW, Solaris Studio C/C++, IBM XL C/C++,[3] GNU C,[4] Clang[5] and Intel C++ Compiler (Linux systems)\n#    define $tls(x) __thread x\n#else\n//   Visual C++,[7] Intel C/C++ (Windows systems),[8] C++Builder, and Digital Mars C++\n#    define $tls(x) __declspec(thread) x\n#endif\n\n// OS utils\n\n#if defined(_WIN32)\n#   define $windows      $yes\n#   define $nwindows     $no\n#else\n#   define $windows      $no\n#   define $nwindows     $yes\n#endif\n\n#ifdef __linux__\n#   define $linux        $yes\n#   define $nlinux       $no\n#else\n#   define $linux        $no\n#   define $nlinux       $yes\n#endif\n\n#ifdef __APPLE__\n#   define $apple        $yes\n#   define $napple       $no\n#else\n#   define $apple        $no\n#   define $napple       $yes\n#endif\n\n#if defined(__APPLE__) && defined(TARGET_OS_MAC)\n#   define $osx          $yes\n#   define $nosx         $no\n#else\n#   define $osx          $no\n#   define $nosx         $yes\n#endif\n\n#if defined(__APPLE__) && (defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR))\n#   define $ios          $yes\n#   define $nios         $no\n#else\n#   define $ios          $no\n#   define $nios         $yes\n#endif\n\n#if defined(__ANDROID_API__)\n#   define $android      $yes\n#   define $nandroid     $no\n#else\n#   define $android      $no\n#   define $nandroid     $yes\n#endif\n\n#if $on($windows) || $on($apple) || $on($linux) || $on($osx) || $on($ios) || $on($android)\n#   define $supported_os         $yes\n#   define $unsupported_os       $no\n#else\n#   define $supported_os         $no\n#   define $unsupported_os       $yes\n#endif\n\n#endif\n\n#ifdef UNDEFINE\n#undef UNDEFINE\n#undef $android\n#undef $apple\n#undef $bits32\n#undef $bits64\n#undef $c\n#undef $cl\n#undef $clang\n#undef $comment\n#undef $cpp\n#undef $cpp03\n#undef $cpp11\n#undef $debug\n#undef $devel\n#undef $exceptions\n#undef $gcc\n#undef $has\n#undef $ios\n#undef $is\n#undef $likely\n#undef $linux\n#undef $nandroid\n#undef $napple\n#undef $ncl\n#undef $nclang\n#undef $nexceptions\n#undef $ngcc\n#undef $nios\n#undef $nlinux\n#undef $no\n#undef $nosx\n#undef $nwindows\n#undef $on\n#undef $osx\n#undef $public\n#undef $quote\n#undef $release\n#undef $supported_compiler\n#undef $supported_os\n#undef $tls\n#undef $todo\n#undef $uncomment\n#undef $unlikely\n#undef $unsupported_compiler\n#undef $unsupported_os\n#undef $warning\n#undef $windows\n#undef $yes\n#ifdef $tod0\n#undef $tod0\n#endif\n#ifdef $t0d0\n#undef $t0d0\n#endif\n#ifdef $w4rning\n#undef $w4rning\n#endif\n#endif\n\n/*\n#include <stdio.h>\nint main() {\n    $c(\n        puts(\"C\");\n    )\n    $cpp(\n        puts(\"C++\");\n        $cpp03(\n            puts(\"C++03\");\n        )\n        $cpp11(\n            puts(\"C++11\");\n        )\n        $exceptions(\n            puts(\"exceptions enabled\");\n        )\n        $nexceptions(\n            puts(\"exceptions disabled\");\n        )\n    )\n\n    $bits32(\n        puts(\"32-bit\");\n    )\n    $bits64(\n        puts(\"64-bit\");\n    )\n\n    $debug(\n        puts(\"unoptimized\");\n    )\n    $release(\n        puts(\"optimized\");\n    )\n\n    $windows(\n        puts(\"windows\");\n    )\n    $ios(\n        puts(\"ios\");\n    )\n    $osx(\n        puts(\"osx\");\n    )\n\n    $warning(\"this line emits a warning\");\n    $todo(\"this line needs a better comment\");\n\n    const char *src = $quote(multi\n    line);\n\n    $comment(\n        puts(\"never compiled\");\n    );\n\n    static $tls(int) thread_local_integer = 1;\n\n    // etc...\n}\n*/\n"
  },
  {
    "path": "tinyzlib.cpp",
    "content": "// tiny zlib inflater. extracted from tigr (credits to Richard Mitton). @todo: remove exceptions\n// - rlyeh, public domain | wtrmrkrlyeh\n\nstatic bool tinyzlib(void *out, unsigned outlen, const void *in, unsigned inlen) {\n    struct State {\n        unsigned bits, count;\n        const unsigned char *in, *inend;\n        unsigned char *out, *outend;\n        unsigned litcodes[288], distcodes[32], lencodes[19];\n        int tlit, tdist, tlen;\n    };\n\n    // Built-in DEFLATE standard tables.\n    const char order[] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };\n    const char lenBits[29+2] = { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,  0,0 };\n    const int lenBase[29+2] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,  0,0 };\n    const char distBits[30+2] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,  0,0 };\n    const int distBase[30+2] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577 };\n\n    auto emit = [](State *s, int len) -> unsigned char * {\n        s->out += len;\n        if(!(s->out <= s->outend)) throw;\n        return s->out-len;\n    };\n\n    auto bits = [](State *s, int n) {\n        int v = s->bits & ((1 << n)-1);\n        s->bits >>= n;\n        s->count -= n;\n        while (s->count < 16) {\n            if(!(s->in != s->inend)) throw;\n            s->bits |= (*s->in++) << s->count;\n            s->count += 8;\n        }\n        return v;\n    };\n\n    auto copy = [&](State *s, const unsigned char *src, int len) {\n        unsigned char *dest = emit(s, len);\n        while (len--) *dest++ = *src++;\n    };\n\n    auto decode = [&](State *s, unsigned tree[], int max) {\n        auto rev16_src = [](unsigned n) -> unsigned {\n            // Table to .\n            static const unsigned char reverseTable[256] = {\n            #define R2(n)    n,     n + 128,     n + 64,     n + 192\n            #define R4(n) R2(n), R2(n +  32), R2(n + 16), R2(n +  48)\n            #define R6(n) R4(n), R4(n +   8), R4(n +  4), R4(n +  12)\n                R6(0), R6(2), R6(1), R6(3)\n            };\n            return (reverseTable[n&0xff] << 8) | reverseTable[(n>>8)&0xff];\n        };\n\n        auto rev16 = [](unsigned n) -> unsigned { // bit-reverse two bytes\n            return (((((n   )&0xff) * 0x0202020202ULL & 0x010884422010ULL) % 1023) << 8)\n                 |  ((((n>>8)&0xff) * 0x0202020202ULL & 0x010884422010ULL) % 1023);\n        };\n\n        // Find the next prefix code.\n        unsigned lo = 0, hi = max, key;\n        unsigned search = (rev16(s->bits) << 16) | 0xffff;\n        while (lo < hi) {\n            unsigned guess = (lo + hi) / 2;\n            if (search < tree[guess]) hi = guess;\n            else lo = guess + 1;\n        }\n\n        // Pull out the key and check it.\n        key = tree[lo-1];\n        if(!(((search^key) >> (32-(key&0xf))) == 0)) throw;\n\n        bits(s, key & 0xf);\n        return (key >> 4) & 0xfff;\n    };\n\n    auto build = [&](State *s, unsigned *tree, unsigned char *lens, int symcount) -> int {\n        int n, codes[16], first[16], counts[16]={0};\n\n        // Frequency count.\n        for (n=0;n<symcount;n++) counts[lens[n]]++;\n\n        // Distribute codes.\n        counts[0] = codes[0] = first[0] = 0;\n        for (n=1;n<=15;n++) {\n            codes[n] = (codes[n-1] + counts[n-1]) << 1;\n            first[n] = first[n-1] + counts[n-1];\n        }\n        if(!(first[15]+counts[15] <= symcount)) throw;\n\n        // Insert keys into the tree for each symbol.\n        for (n=0;n<symcount;n++) {\n            int len = lens[n];\n            if (len != 0) {\n                int code = codes[len]++, slot = first[len]++;\n                tree[slot] = (code << (32-len)) | (n << 4) | len;\n            }\n        }\n\n        return first[15];\n    };\n\n    auto block = [&](State *s) {\n        auto run = [&](State *s, int sym) {\n            int length = bits(s, lenBits[sym]) + lenBase[sym];\n            int dsym = decode(s, s->distcodes, s->tdist);\n            int offs = bits(s, distBits[dsym]) + distBase[dsym];\n            copy(s, s->out - offs, length);\n        };\n        for (;;) {\n            int sym = decode(s, s->litcodes, s->tlit);\n                 if (sym < 256) *emit(s, 1) = (unsigned char)sym;\n            else if (sym > 256) run(s, sym-257);\n            else break;\n        }\n    };\n\n    auto stored = [&](State *s) { // Uncompressed data block\n        int len; \n        bits(s, s->count & 7);\n        len = bits(s, 16);\n        if(!(((len^s->bits)&0xffff) == 0xffff)) throw;\n        if(!(s->in + len <= s->inend)) throw;\n\n        copy(s, s->in, len);\n        s->in += len;\n        bits(s, 16);\n    };\n\n    auto fixed = [&](State *s) { // Fixed set of Huffman codes\n        int n;\n        unsigned char lens[288+32];\n        for (n=  0;n<=143;n++) lens[n] = 8;\n        for (n=144;n<=255;n++) lens[n] = 9;\n        for (n=256;n<=279;n++) lens[n] = 7;\n        for (n=280;n<=287;n++) lens[n] = 8;\n        for (n=0;n<32;n++) lens[288+n] = 5;\n\n        // Build lit/dist trees.\n        s->tlit  = build(s, s->litcodes, lens, 288);\n        s->tdist = build(s, s->distcodes, lens+288, 32);\n    };\n\n    auto dynamic = [&](State *s) {\n        int n, i, nlit, ndist, nlen;\n        unsigned char lenlens[19] = {0}, lens[288+32];\n        nlit = 257 + bits(s, 5);\n        ndist = 1 + bits(s, 5);\n        nlen = 4 + bits(s, 4);\n        for (n=0;n<nlen;n++) {\n            lenlens[order[n]] = (unsigned char)bits(s, 3);\n        }\n\n        // Build the tree for decoding code lengths.\n        s->tlen = build(s, s->lencodes, lenlens, 19);\n\n        // Decode code lengths.\n        for (n=0;n<nlit+ndist;) {\n            int sym = decode(s, s->lencodes, s->tlen);\n            switch (sym) {\n            case 16: for (i =  3+bits(s,2); i; i--,n++) lens[n] = lens[n-1]; break;\n            case 17: for (i =  3+bits(s,3); i; i--,n++) lens[n] = 0; break;\n            case 18: for (i = 11+bits(s,7); i; i--,n++) lens[n] = 0; break;\n            default: lens[n++] = (unsigned char)sym; break;\n            }\n        }\n\n        // Build lit/dist trees.\n        s->tlit  = build(s, s->litcodes, lens, nlit);\n        s->tdist = build(s, s->distcodes, lens+nlit, ndist);\n    };\n\n    struct State s0 = {}, *s = &s0;\n\n    // We assume we can buffer 2 extra bytes from off the end of 'in'.\n    s->in  = (unsigned char *)in;  s->inend  = s->in  + inlen + 2;\n    s->out = (unsigned char *)out; s->outend = s->out + outlen;\n    s->bits = 0; s->count = 0; bits(s, 0);\n\n    try {\n        for( int last = 0; !last;  ) {\n            last = bits(s, 1);\n            switch (bits(s, 2)) {\n            case 0: stored(s); break;\n            case 1: fixed(s); block(s); break;\n            case 2: dynamic(s); block(s); break;\n            case 3: return 0;\n            }\n        }\n        return true;\n    }\n    catch(...) \n    {}\n\n    return false;\n}\n\n"
  },
  {
    "path": "vault/; ds",
    "content": "\n"
  },
  {
    "path": "vault/_test.c",
    "content": "// compilation test\n// - rlyeh, public domain\n\n#define ALL_C\n#include \"all.c\"\n\nint main() \n{}\n"
  },
  {
    "path": "vault/all.c",
    "content": "// - rlyeh, public domain\n\n#ifdef ALL_C\n#define C_C\n#define OS_C\n#define DS_C\n#define SYN_C\n#define BIN_C\n#define BUF_C\n#define NET_C\n#endif\n\n#include \"c.c\"\n#include \"os.c\"\n#include \"ds.c\"\n#include \"syn.c\"\n#include \"bin.c\"\n#include \"buf.c\"\n#include \"net.c\"\n"
  },
  {
    "path": "vault/bin.c",
    "content": "// - rlyeh, public domain\n\n#ifdef BIN_C\n#define DBKV_C\n#define JSON5_C\n#endif\n\n#include \"os.c\"\n#include \"bin_dbkv.c\"\n#include \"bin_json5.c\"\n"
  },
  {
    "path": "vault/bin_dbkv.c",
    "content": "// KISSDB written by Adam Ierymenko <adam.ierymenko@zerotier.com>\n// KISSDB is in the public domain and is distributed with NO WARRANTY.\n// http://creativecommons.org/publicdomain/zero/1.0/\n\n#ifndef DBKV_H\n#define DBKV_H\n#include <stdbool.h>\n\n#if 0\n#if !defined(DBKV_LEN_KEY) && !defined(DBKV_LEN_VALUE)\n// UDP packet size  576 (IPv4) = UDP payload  508 + UDP header 8 + IP header 60\n// UDP packet size 1280 (IPv6) = UDP payload 1212 + UDP header 8 + IP header 60\nenum {\n    DBKV_HASH_BUCKET = 508 /*1024*/,\n    DBKV_LEN_KEY = 31+1, /*8*/\n    DBKV_LEN_VALUE = 508 - DBKV_LEN_KEY /*64*/\n};\n#endif\n#else\nenum {\n    DBKV_HASH_BUCKET = 1024,\n    DBKV_LEN_KEY = 8,\n    DBKV_LEN_VALUE = 64\n};\n#endif\n\ntypedef char dbkv_key[DBKV_LEN_KEY];\ntypedef char dbkv_val[DBKV_LEN_VALUE];\n\nbool dbkv_read( const char *dbfile, const char *keystr, char *val );\nbool dbkv_write( const char *dbfile, const char *keystr, const char *val );\n\n#endif\n\n#ifdef DBKV_C\n#pragma once\n#include <stdint.h>\n//#include \"detect/detect_memory.c\" // realloc\n\n#if 1 //ndef $\n#ifndef _FILE_OFFSET_BITS\n#define _FILE_OFFSET_BITS 64\n#endif\n#include <stdio.h>\n#  if !defined fseeko && defined _MSC_VER // _MSC_VER\n#   define fseeko _fseeki64\n#   define ftello _ftelli64\n#  elif !defined fseeko\n#   define fseeko fseek\n#   define ftello ftell\n#  endif\n#  if !defined fopen_s && !defined _MSC_VER\n#   define fopen_s(fp,path,mode) ( (*(fp) = fopen( path, mode ) ) )\n#endif\n#endif\n\n/* (Keep It) Simple Stupid Database\n *\n * Written by Adam Ierymenko <adam.ierymenko@zerotier.com>\n * KISSDB is in the public domain and is distributed with NO WARRANTY.\n * http://creativecommons.org/publicdomain/zero/1.0/\n *\n * Note: big-endian systems will need changes to implement byte swapping\n * on hash table file I/O. Or you could just use it as-is if you don't care\n * that your database files will be unreadable on little-endian systems. \n *\n * -----\n *\n * KISSDB file format (version 2)\n * Author: Adam Ierymenko <adam.ierymenko@zerotier.com>\n * http://creativecommons.org/publicdomain/zero/1.0/\n *\n * In keeping with the goal of minimalism the file format is very simple, the\n * sort of thing that would be given as an example in an introductory course in\n * data structures. It's a basic hash table that adds additional pages of hash\n * table entries on collision.\n *\n * It consists of a 28 byte header followed by a series of hash tables and data.\n * All integer values are stored in the native word order of the target\n * architecture (in the future the code might be fixed to make everything\n * little-endian if anyone cares about that).\n *\n * The header consists of the following fields:\n *\n * [0-3]   magic numbers: (ASCII) 'K', 'd', 'B', KISSDB_VERSION (currently 2)\n * [4-11]  64-bit hash table size in entries\n * [12-19] 64-bit key size in bytes\n * [20-27] 64-bit value size in bytes\n *\n * Hash tables are arrays of [hash table size + 1] 64-bit integers. The extra\n * entry, if nonzero, is the offset in the file of the next hash table, forming\n * a linked list of hash tables across the file.\n *\n * Immediately following the header, the first hash table will be written when\n * the first key/value is added. The algorithm for adding new entries is as\n * follows:\n *\n * (1) The key is hashed using a 64-bit variant of the DJB2 hash function, and\n *     this is taken modulo hash table size to get a bucket number.\n * (2) Hash tables are checked in order, starting with the first hash table,\n *     until a zero (empty) bucket is found. If one is found, skip to step (4).\n * (3) If no empty buckets are found in any hash table, a new table is appended\n *     to the file and the final pointer in the previous hash table is set to\n *     its offset. (In the code the update of the next hash table pointer in\n *     the previous hash table happens last, after the whole write is complete,\n *     to avoid corruption on power loss.)\n * (4) The key and value are appended, in order with no additional meta-data,\n *     to the database file. Before appending the offset in the file stream\n *     where they will be stored is saved. After appending, this offset is\n *     written to the empty hash table bucket we chose in steps 2/3. Hash table\n *     updates happen last to avoid corruption if the write does not complete.\n *\n * Lookup of a key/value pair occurs as follows:\n *\n * (1) The key is hashed and taken modulo hash table size to get a bucket\n *     number.\n * (2) If this bucket's entry in the hash table is nonzero, the key at the\n *     offset specified by this bucket is compared to the key being looked up.\n *     If they are equal, the value is read and returned.\n * (3) If the keys are not equal, the next hash table is checked and step (2)\n *     is repeated. If an empty bucket is encountered or if we run out of hash\n *     tables, the key was not found.\n *\n * To update an existing value, its location is looked up and the value portion\n * of the entry is rewritten.\n */\n\n// --- kissdb.h ---\n\n/* (Keep It) Simple Stupid Database\n *\n * Written by Adam Ierymenko <adam.ierymenko@zerotier.com>\n * KISSDB is in the public domain and is distributed with NO WARRANTY.\n *\n * http://creativecommons.org/publicdomain/zero/1.0/ */\n\n/**\n * Version: 2\n *\n * This is the file format identifier, and changes any time the file\n * format changes. The code version will be this dot something, and can\n * be seen in tags in the git repository.\n */\n#define KISSDB_VERSION 2\n\n/**\n * KISSDB database state\n *\n * These fields can be read by a user, e.g. to look up key_size and\n * value_size, but should never be changed.\n */\ntypedef struct {\n    unsigned long hash_table_size;\n    unsigned long key_size;\n    unsigned long value_size;\n    unsigned long hash_table_size_bytes;\n    unsigned long num_hash_tables;\n    uint64_t *hash_tables;\n    FILE *f;\n} KISSDB;\n\nenum { KISSDB_ERROR_IO = -1 };                   // I/O error or file not found\nenum { KISSDB_ERROR_MALLOC = -2 };               // Out of memory\nenum { KISSDB_ERROR_INVALID_PARAMETERS = -3 };   // Invalid paramters (e.g. missing _size paramters on init to create database)\nenum { KISSDB_ERROR_CORRUPT_DBFILE = -4 };       // Database file appears corrupt\nenum { KISSDB_OPEN_MODE_RDONLY = 1 };            // Open mode: read only\nenum { KISSDB_OPEN_MODE_RDWR = 2 };              // Open mode: read/write\nenum { KISSDB_OPEN_MODE_RWCREAT = 3 };           // Open mode: read/write, create if doesn't exist\nenum { KISSDB_OPEN_MODE_RWREPLACE = 4 };         // Open mode: truncate database, open for reading and writing\n\n/**\n * Open database\n *\n * The three _size parameters must be specified if the database could\n * be created or re-created. Otherwise an error will occur. If the\n * database already exists, these parameters are ignored and are read\n * from the database. You can check the struture afterwords to see what\n * they were.\n *\n * @param db Database struct\n * @param path Path to file\n * @param mode One of the KISSDB_OPEN_MODE constants\n * @param hash_table_size Size of hash table in 64-bit entries (must be >0)\n * @param key_size Size of keys in bytes\n * @param value_size Size of values in bytes\n * @return 0 on success, nonzero on error\n */\nstatic int KISSDB_open(\n    KISSDB *db,\n    const char *path,\n    int mode,\n    unsigned long hash_table_size,\n    unsigned long key_size,\n    unsigned long value_size);\n\n/**\n * Close database\n *\n * @param db Database struct\n */\nstatic void KISSDB_close(KISSDB *db);\n\n/**\n * Get an entry\n *\n * @param db Database struct\n * @param key Key (key_size bytes)\n * @param vbuf Value buffer (value_size bytes capacity)\n * @return -1 on I/O error, 0 on success, 1 on not found\n */\nstatic int KISSDB_get(KISSDB *db,const void *key,void *vbuf);\n\n/**\n * Put an entry (overwriting it if it already exists)\n *\n * In the already-exists case the size of the database file does not\n * change.\n *\n * @param db Database struct\n * @param key Key (key_size bytes)\n * @param value Value (value_size bytes)\n * @return -1 on I/O error, 0 on success\n */\nstatic int KISSDB_put(KISSDB *db,const void *key,const void *value);\n\n/**\n * Cursor used for iterating over all entries in database\n */\ntypedef struct {\n    KISSDB *db;\n    unsigned long h_no;\n    unsigned long h_idx;\n} KISSDB_Iterator;\n\n/**\n * Initialize an iterator\n *\n * @param db Database struct\n * @param i Iterator to initialize\n */\nstatic void KISSDB_Iterator_init(KISSDB *db,KISSDB_Iterator *dbi);\n\n/**\n * Get the next entry\n *\n * The order of entries returned by iterator is undefined. It depends on\n * how keys hash.\n *\n * @param Database iterator\n * @param kbuf Buffer to fill with next key (key_size bytes)\n * @param vbuf Buffer to fill with next value (value_size bytes)\n * @return 0 if there are no more entries, negative on error, positive if an kbuf/vbuf have been filled\n */\nstatic int KISSDB_Iterator_next(KISSDB_Iterator *dbi,void *kbuf,void *vbuf);\n\n// --- kissdb.c ---\n\n#include <string.h>\n#include <stdlib.h>\n#include <stdint.h>\n\n#define KISSDB_HEADER_SIZE ((sizeof(uint64_t) * 3) + 4)\n\n/* djb2 hash function */\nstatic uint64_t KISSDB_hash(const void *b,unsigned long len)\n{\n    unsigned long i;\n    uint64_t hash = 5381;\n    for(i=0;i<len;++i)\n        hash = ((hash << 5) + hash) + (uint64_t)(((const uint8_t *)b)[i]);\n    return hash;\n}\n\nstatic int KISSDB_open(\n    KISSDB *db,\n    const char *path,\n    int mode,\n    unsigned long hash_table_size,\n    unsigned long key_size,\n    unsigned long value_size)\n{\n    uint64_t tmp;\n    uint8_t tmp2[4];\n    uint64_t *httmp;\n    uint64_t *hash_tables_rea;\n\n    db->f = (FILE *)0;\n    fopen_s(&db->f,path,((mode == KISSDB_OPEN_MODE_RWREPLACE) ? \"w+b\" : (((mode == KISSDB_OPEN_MODE_RDWR)||(mode == KISSDB_OPEN_MODE_RWCREAT)) ? \"r+b\" : \"rb\")));\n    if (!db->f) {\n        if (mode == KISSDB_OPEN_MODE_RWCREAT) {\n            db->f = (FILE *)0;\n            fopen_s(&db->f,path,\"w+b\");\n        }\n        if (!db->f)\n            return KISSDB_ERROR_IO;\n    }\n\n    if (fseeko(db->f,0,SEEK_END)) {\n        fclose(db->f);\n        return KISSDB_ERROR_IO;\n    }\n    if (ftello(db->f) < KISSDB_HEADER_SIZE) {\n        /* write header if not already present */\n        if ((hash_table_size)&&(key_size)&&(value_size)) {\n            if (fseeko(db->f,0,SEEK_SET)) { fclose(db->f); return KISSDB_ERROR_IO; }\n            tmp2[0] = 'K'; tmp2[1] = 'd'; tmp2[2] = 'B'; tmp2[3] = KISSDB_VERSION;\n            if (fwrite(tmp2,4,1,db->f) != 1) { fclose(db->f); return KISSDB_ERROR_IO; }\n            tmp = hash_table_size;\n            if (fwrite(&tmp,sizeof(uint64_t),1,db->f) != 1) { fclose(db->f); return KISSDB_ERROR_IO; }\n            tmp = key_size;\n            if (fwrite(&tmp,sizeof(uint64_t),1,db->f) != 1) { fclose(db->f); return KISSDB_ERROR_IO; }\n            tmp = value_size;\n            if (fwrite(&tmp,sizeof(uint64_t),1,db->f) != 1) { fclose(db->f); return KISSDB_ERROR_IO; }\n            fflush(db->f);\n        } else {\n            fclose(db->f);\n            return KISSDB_ERROR_INVALID_PARAMETERS;\n        }\n    } else {\n        if (fseeko(db->f,0,SEEK_SET)) { fclose(db->f); return KISSDB_ERROR_IO; }\n        if (fread(tmp2,4,1,db->f) != 1) { fclose(db->f); return KISSDB_ERROR_IO; }\n        if ((tmp2[0] != 'K')||(tmp2[1] != 'd')||(tmp2[2] != 'B')||(tmp2[3] != KISSDB_VERSION)) {\n            fclose(db->f);\n            return KISSDB_ERROR_CORRUPT_DBFILE;\n        }\n        if (fread(&tmp,sizeof(uint64_t),1,db->f) != 1) { fclose(db->f); return KISSDB_ERROR_IO; }\n        if (!tmp) {\n            fclose(db->f);\n            return KISSDB_ERROR_CORRUPT_DBFILE;\n        }\n        hash_table_size = (unsigned long)tmp;\n        if (fread(&tmp,sizeof(uint64_t),1,db->f) != 1) { fclose(db->f); return KISSDB_ERROR_IO; }\n        if (!tmp) {\n            fclose(db->f);\n            return KISSDB_ERROR_CORRUPT_DBFILE;\n        }\n        key_size = (unsigned long)tmp;\n        if (fread(&tmp,sizeof(uint64_t),1,db->f) != 1) { fclose(db->f); return KISSDB_ERROR_IO; }\n        if (!tmp) {\n            fclose(db->f);\n            return KISSDB_ERROR_CORRUPT_DBFILE;\n        }\n        value_size = (unsigned long)tmp;\n    }\n\n    db->hash_table_size = hash_table_size;\n    db->key_size = key_size;\n    db->value_size = value_size;\n    db->hash_table_size_bytes = sizeof(uint64_t) * (hash_table_size + 1); /* [hash_table_size] == next table */\n\n    httmp = MALLOC(db->hash_table_size_bytes);\n    if (!httmp) {\n        fclose(db->f);\n        return KISSDB_ERROR_MALLOC;\n    }\n    db->num_hash_tables = 0;\n    db->hash_tables = (uint64_t *)0;\n    while (fread(httmp,db->hash_table_size_bytes,1,db->f) == 1) {\n        hash_tables_rea = REALLOC(db->hash_tables,db->hash_table_size_bytes * (db->num_hash_tables + 1));\n        if (!hash_tables_rea) {\n            KISSDB_close(db);\n            FREE(httmp);\n            return KISSDB_ERROR_MALLOC;\n        }\n        db->hash_tables = hash_tables_rea;\n\n        memcpy(((uint8_t *)db->hash_tables) + (db->hash_table_size_bytes * db->num_hash_tables),httmp,db->hash_table_size_bytes);\n        ++db->num_hash_tables;\n        if (httmp[db->hash_table_size]) {\n            if (fseeko(db->f,httmp[db->hash_table_size],SEEK_SET)) {\n                KISSDB_close(db);\n                FREE(httmp);\n                return KISSDB_ERROR_IO;\n            }\n        } else break;\n    }\n    FREE(httmp);\n\n    return 0;\n}\n\nstatic void KISSDB_close(KISSDB *db)\n{\n    if (db->hash_tables)\n        FREE(db->hash_tables);\n    if (db->f)\n        fclose(db->f);\n    memset(db,0,sizeof(KISSDB));\n}\n\nstatic int KISSDB_get(KISSDB *db,const void *key,void *vbuf)\n{\n    uint8_t tmp[4096];\n    const uint8_t *kptr;\n    unsigned long klen,i;\n    uint64_t hash = KISSDB_hash(key,db->key_size) % (uint64_t)db->hash_table_size;\n    uint64_t offset;\n    uint64_t *cur_hash_table;\n    long n;\n\n    cur_hash_table = db->hash_tables;\n    for(i=0;i<db->num_hash_tables;++i) {\n        offset = cur_hash_table[hash];\n        if (offset) {\n            if (fseeko(db->f,offset,SEEK_SET))\n                return KISSDB_ERROR_IO;\n\n            kptr = (const uint8_t *)key;\n            klen = db->key_size;\n            while (klen) {\n                n = (long)fread(tmp,1,(klen > sizeof(tmp)) ? sizeof(tmp) : klen,db->f);\n                if (n > 0) {\n                    if (memcmp(kptr,tmp,n))\n                        goto get_no_match_next_hash_table;\n                    kptr += n;\n                    klen -= (unsigned long)n;\n                } else return 1; /* not found */\n            }\n\n            if (fread(vbuf,db->value_size,1,db->f) == 1)\n                return 0; /* success */\n            else return KISSDB_ERROR_IO;\n        } else return 1; /* not found */\nget_no_match_next_hash_table:\n        cur_hash_table += db->hash_table_size + 1;\n    }\n\n    return 1; /* not found */\n}\n\nstatic int KISSDB_put(KISSDB *db,const void *key,const void *value)\n{\n    uint8_t tmp[4096];\n    const uint8_t *kptr;\n    unsigned long klen,i;\n    uint64_t hash = KISSDB_hash(key,db->key_size) % (uint64_t)db->hash_table_size;\n    uint64_t offset;\n    uint64_t htoffset,lasthtoffset;\n    uint64_t endoffset;\n    uint64_t *cur_hash_table;\n    uint64_t *hash_tables_rea;\n    long n;\n\n    lasthtoffset = htoffset = KISSDB_HEADER_SIZE;\n    cur_hash_table = db->hash_tables;\n    for(i=0;i<db->num_hash_tables;++i) {\n        offset = cur_hash_table[hash];\n        if (offset) {\n            /* rewrite if already exists */\n            if (fseeko(db->f,offset,SEEK_SET))\n                return KISSDB_ERROR_IO;\n\n            kptr = (const uint8_t *)key;\n            klen = db->key_size;\n            while (klen) {\n                n = (long)fread(tmp,1,(klen > sizeof(tmp)) ? sizeof(tmp) : klen,db->f);\n                if (n > 0) {\n                    if (memcmp(kptr,tmp,n))\n                        goto put_no_match_next_hash_table;\n                    kptr += n;\n                    klen -= (unsigned long)n;\n                }\n            }\n\n            /* C99 spec demands seek after fread(), required for Windows */\n            fseeko(db->f,0,SEEK_CUR);\n \n            if (fwrite(value,db->value_size,1,db->f) == 1) {\n                fflush(db->f);\n                return 0; /* success */\n            } else return KISSDB_ERROR_IO;\n        } else {\n            /* add if an empty hash table slot is discovered */\n            if (fseeko(db->f,0,SEEK_END))\n                return KISSDB_ERROR_IO;\n            endoffset = ftello(db->f);\n\n            if (fwrite(key,db->key_size,1,db->f) != 1)\n                return KISSDB_ERROR_IO;\n            if (fwrite(value,db->value_size,1,db->f) != 1)\n                return KISSDB_ERROR_IO;\n\n            if (fseeko(db->f,htoffset + (sizeof(uint64_t) * hash),SEEK_SET))\n                return KISSDB_ERROR_IO;\n            if (fwrite(&endoffset,sizeof(uint64_t),1,db->f) != 1)\n                return KISSDB_ERROR_IO;\n            cur_hash_table[hash] = endoffset;\n\n            fflush(db->f);\n\n            return 0; /* success */\n        }\nput_no_match_next_hash_table:\n        lasthtoffset = htoffset;\n        htoffset = cur_hash_table[db->hash_table_size];\n        cur_hash_table += (db->hash_table_size + 1);\n    }\n\n    /* if no existing slots, add a new page of hash table entries */\n    if (fseeko(db->f,0,SEEK_END))\n        return KISSDB_ERROR_IO;\n    endoffset = ftello(db->f);\n\n    hash_tables_rea = REALLOC(db->hash_tables,db->hash_table_size_bytes * (db->num_hash_tables + 1));\n    if (!hash_tables_rea)\n        return KISSDB_ERROR_MALLOC;\n    db->hash_tables = hash_tables_rea;\n    cur_hash_table = &(db->hash_tables[(db->hash_table_size + 1) * db->num_hash_tables]);\n    memset(cur_hash_table,0,db->hash_table_size_bytes);\n\n    cur_hash_table[hash] = endoffset + db->hash_table_size_bytes; /* where new entry will go */\n\n    if (fwrite(cur_hash_table,db->hash_table_size_bytes,1,db->f) != 1)\n        return KISSDB_ERROR_IO;\n\n    if (fwrite(key,db->key_size,1,db->f) != 1)\n        return KISSDB_ERROR_IO;\n    if (fwrite(value,db->value_size,1,db->f) != 1)\n        return KISSDB_ERROR_IO;\n\n    if (db->num_hash_tables) {\n        if (fseeko(db->f,lasthtoffset + (sizeof(uint64_t) * db->hash_table_size),SEEK_SET))\n            return KISSDB_ERROR_IO;\n        if (fwrite(&endoffset,sizeof(uint64_t),1,db->f) != 1)\n            return KISSDB_ERROR_IO;\n        db->hash_tables[((db->hash_table_size + 1) * (db->num_hash_tables - 1)) + db->hash_table_size] = endoffset;\n    }\n\n    ++db->num_hash_tables;\n\n    fflush(db->f);\n\n    return 0; /* success */\n}\n\nstatic void KISSDB_Iterator_init(KISSDB *db,KISSDB_Iterator *dbi)\n{\n    dbi->db = db;\n    dbi->h_no = 0;\n    dbi->h_idx = 0;\n}\n\nstatic int KISSDB_Iterator_next(KISSDB_Iterator *dbi,void *kbuf,void *vbuf)\n{\n    uint64_t offset;\n\n    if ((dbi->h_no < dbi->db->num_hash_tables)&&(dbi->h_idx < dbi->db->hash_table_size)) {\n        while (!(offset = dbi->db->hash_tables[((dbi->db->hash_table_size + 1) * dbi->h_no) + dbi->h_idx])) {\n            if (++dbi->h_idx >= dbi->db->hash_table_size) {\n                dbi->h_idx = 0;\n                if (++dbi->h_no >= dbi->db->num_hash_tables)\n                    return 0;\n            }\n        }\n        if (fseeko(dbi->db->f,offset,SEEK_SET))\n            return KISSDB_ERROR_IO;\n        if (fread(kbuf,dbi->db->key_size,1,dbi->db->f) != 1)\n            return KISSDB_ERROR_IO;\n        if (fread(vbuf,dbi->db->value_size,1,dbi->db->f) != 1)\n            return KISSDB_ERROR_IO;\n        if (++dbi->h_idx >= dbi->db->hash_table_size) {\n            dbi->h_idx = 0;\n            ++dbi->h_no;\n        }\n        return 1;\n    }\n\n    return 0;\n}\n\n#endif\n\n#ifdef DBKV_BENCH\n#include <time.h>\n#include <inttypes.h>\n\n#ifdef _MSC_VER\n#include <omp.h>\n#define clock_t double\n#define clock omp_get_wtime\n#undef CLOCKS_PER_SEC\n#define CLOCKS_PER_SEC 1.0\n#endif\n\nint main(int argc,char **argv)\n{\n    #ifndef N\n    enum { N = 100000 };\n    #endif\n    uint64_t i,j;\n    uint64_t v[8];\n    KISSDB db;\n    KISSDB_Iterator dbi;\n    char *got_all_values = malloc(N);\n    int q;\n\n    clock_t begin, end;\n\n    #ifdef STDIO2\n    if( argc < 2 ) {\n        printf(\"%s [file.db]\\n\", argv[0]);\n        printf(\"%s [mem://file.db]\\n\", argv[0]);\n        exit(0);\n    }\n    const char *dbfile = argv[1];\n    #else\n    const char *dbfile = \"test.db\";\n    #endif\n\n    begin = clock();\n\n    printf(\"Opening new empty database %s...\\n\", dbfile);\n    if (KISSDB_open(&db,dbfile,KISSDB_OPEN_MODE_RWREPLACE,1024,8,sizeof(v))) {\n        printf(\"KISSDB_open failed\\n\");\n        return 1;\n    }\n\n    end = clock();\n    {\n        double sec = (end - begin)/(double)CLOCKS_PER_SEC;\n        printf(\"OK! %5.2fs\\n\", sec);\n    }\n    begin = clock();\n\n    printf(\"Putting %d 64-byte values...\\n\", N);\n    for(i=0;i<N;++i) {\n        for(j=0;j<8;++j)\n            v[j] = i;\n        if (KISSDB_put(&db,&i,v)) {\n            printf(\"KISSDB_put failed (%\"PRIu64\")\\n\",i);\n            return 1;\n        }\n    }\n\n    end = clock();\n    {\n        int ops = N;\n        double sec = (end - begin)/(double)CLOCKS_PER_SEC;\n        printf(\"OK! %d ops in %5.2fs, %5.2fops/s, %5.2fops/frame\\n\", ops, sec, ops/sec, ops/sec/60);\n    }\n    begin = clock();\n\n    printf(\"Getting %d 64-byte values...\\n\", N);\n    for(i=0;i<N;++i) {\n        if ((q = KISSDB_get(&db,&i,v))) {\n            printf(\"KISSDB_get (2) failed (%\"PRIu64\") (%d)\\n\",i,q);\n            return 1;\n        }\n        for(j=0;j<8;++j) {\n            if (v[j] != i) {\n                printf(\"KISSDB_get (2) failed, bad data (%\"PRIu64\")\\n\",i);\n                return 1;\n            }\n        }\n    }\n\n    end = clock();\n    {\n        int ops = N;\n        double sec = (end - begin)/(double)CLOCKS_PER_SEC;\n        printf(\"OK! %d ops in %5.2fs, %5.2fops/s, %5.2fops/frame\\n\", ops, sec, ops/sec, ops/sec/60);\n    }\n    begin = clock();\n\n    printf(\"Closing and re-opening database in read-only mode...\\n\");\n    KISSDB_close(&db);\n    if (KISSDB_open(&db,dbfile,KISSDB_OPEN_MODE_RDONLY,1024,8,sizeof(v))) {\n        printf(\"KISSDB_open failed\\n\");\n        return 1;\n    }\n\n    end = clock();\n    {\n        double sec = (end - begin)/(double)CLOCKS_PER_SEC;\n        printf(\"OK! %5.2fs\\n\", sec);\n    }\n    begin = clock();\n\n    printf(\"Getting %d 64-byte values...\\n\", N);\n    for(i=0;i<N;++i) {\n        if ((q = KISSDB_get(&db,&i,v))) {\n            printf(\"KISSDB_get (3) failed (%\"PRIu64\") (%d)\\n\",i,q);\n            return 1;\n        }\n        for(j=0;j<8;++j) {\n            if (v[j] != i) {\n                printf(\"KISSDB_get (3) failed, bad data (%\"PRIu64\")\\n\",i);\n                return 1;\n            }\n        }\n    }\n\n    end = clock();\n    {\n        int ops = N;\n        double sec = (end - begin)/(double)CLOCKS_PER_SEC;\n        printf(\"OK! %d ops in %5.2fs, %5.2fops/s, %5.2fops/frame\\n\", ops, sec, ops/sec, ops/sec/60);\n    }\n    begin = clock();\n\n    printf(\"Iterating %d 64-byte values...\\n\", N);\n    KISSDB_Iterator_init(&db,&dbi);\n    i = 0xdeadbeef;\n    memset(got_all_values,0,sizeof(N));\n    while (KISSDB_Iterator_next(&dbi,&i,&v) > 0) {\n        if (i < N)\n            got_all_values[i] = 1;\n        else {\n            printf(\"KISSDB_Iterator_next failed, bad data (%\"PRIu64\")\\n\",i);\n            return 1;\n        }\n    }\n    for(i=0;i<N;++i) {\n        if (!got_all_values[i]) {\n            printf(\"KISSDB_Iterator failed, missing value index %\"PRIu64\"\\n\",i);\n            return 1;\n        }\n    }\n\n    KISSDB_close(&db);\n\n    end = clock();\n    {\n        int ops = N;\n        double sec = (end - begin)/(double)CLOCKS_PER_SEC;\n        printf(\"OK! %d ops in %5.2fs, %5.2fops/s, %5.2fops/frame\\n\", ops, sec, ops/sec, ops/sec/60);\n    }\n    begin = clock();\n\n    return 0;\n}\n#define main main__\n#endif\n\n#ifdef DBKV_C\n#pragma once\nbool dbkv_read( const char *dbfile, const char *keystr, char *val ) {\n    KISSDB kdb = {0};\n    int ok = 0 == KISSDB_open( &kdb, dbfile, KISSDB_OPEN_MODE_RWCREAT, DBKV_HASH_BUCKET, DBKV_LEN_KEY, DBKV_LEN_VALUE);\n    if( ok ) {\n        dbkv_key key = {0};\n        strcpy( key, keystr ); //sprintf(key, \"%.*s\", strlen(keystr) > DBKV_LEN_KEY ? DBKV_LEN_KEY : strlen(keystr), keystr);\n\n        int result = KISSDB_get( &kdb, key, val ), not_found = result > 0; // -1:I/O error, 0:ok, 1:not found\n        ok = result >= 0; //printf(\"rd %s=%s (found: %d) (rc: %d)\\n\", key, val, !not_found, result);\n\n        KISSDB_close( &kdb );\n    }\n    return !!ok;\n}\nbool dbkv_write( const char *dbfile, const char *keystr, const char *val ) {\n    KISSDB kdb = {0};\n    int ok = 0 == KISSDB_open( &kdb, dbfile, KISSDB_OPEN_MODE_RWCREAT, DBKV_HASH_BUCKET, DBKV_LEN_KEY, DBKV_LEN_VALUE);\n    if( ok ) {\n        dbkv_key key = {0};\n        strcpy( key, keystr ); //sprintf(key, \"%.*s\", strlen(keystr) > DBKV_LEN_KEY ? DBKV_LEN_KEY : strlen(keystr), keystr);\n\n        int result = KISSDB_put( &kdb, key, val ); // -1:I/O error, 0:ok\n        ok = result >= 0; //printf(\"wr (rc: %d)\\n\", result);\n\n        KISSDB_close( &kdb );\n    }\n    return !!ok;\n}\n\n#ifdef DBKV_DEMO\n#include <stdio.h>\nint main( int argc, char **argv ) {\n    dbkv_val val = \"0\"; // default value, if not found\n    dbkv_read( \"db.kvs\", \"/hello\", val );\n\n    printf(\"/hello=%s\\n\", val);\n\n    val[0] ++; if( val[0] > '9' ) val[0] = '0';\n    dbkv_write( \"db.kvs\", \"/hello\", val );\n}\n#define main main__\n#endif // KBDV_DEMO\n#endif // KBDV_C\n\n"
  },
  {
    "path": "vault/bin_json5.c",
    "content": "// JSON5 + SJSON parser module\n//\n// License:\n// This software is dual-licensed to the public domain and under the following\n// license: you are granted a perpetual, irrevocable license to copy, modify,\n// publish, and distribute this file as you see fit.\n// No warranty is implied, use at your own risk.\n//\n// Credits:\n// Dominik Madarasz (original code) (GitHub: zaklaus)\n// r-lyeh (fork)\n\n#ifndef JSON5_H\n#define JSON5_H\n\n#ifndef JSON5_ASSERT\n#define JSON5_ASSERT do { printf(\"JSON5: Error L%d while parsing '%c' in '%.16s'\\n\", __LINE__, p[0], p); assert(0); } while(0)\n#endif\n\n#include <stdint.h>\n#include <stdio.h>\n\ntypedef enum json5_type {\n    json5_undefined, // 0\n    json5_null,      // 1\n    json5_bool,      // 2\n    json5_object,    // 3\n    json5_string,    // 4\n    json5_array,     // 5\n    json5_integer,   // 6\n    json5_real,      // 7\n} json5_type;\n\ntypedef struct json5 {\n    char*      name;\n#ifdef NDEBUG\n    unsigned   type : 3;\n#else\n    json5_type type;\n#endif\n    unsigned   count : 29;\n    union {\n        struct json5* array;\n        struct json5* nodes;\n        int64_t   integer;\n        double    real;\n        char*     string;\n        int       boolean;\n    };\n} json5;\n\nchar* json5_parse(json5 *root, char *source, int flags);\nvoid  json5_write(FILE *fp, const json5 *root);\nvoid  json5_free(json5 *root);\n\n#endif // JSON5_H\n\n// json5 ----------------------------------------------------------------------\n\n#ifdef JSON5_C\n#pragma once\n#include <assert.h>\n#include <ctype.h>\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\nchar *json5__trim(char *p) {\n    while (*p) {\n        /**/ if( isspace(*p) ) ++p;\n        else if( p[0] == '/' && p[1] == '*' ) { // skip C comment\n            for( p += 2; *p && !(p[0] == '*' && p[1] == '/'); ++p) {}\n            if( *p ) p += 2;\n        }\n        else if( p[0] == '/' && p[1] == '/' ) { // skip C++ comment\n            for( p += 2; *p && p[0] != '\\n'; ++p) {}\n            if( *p ) ++p;\n        }\n        else break;\n    }\n    return p;\n}\n\nchar *json5__parse_value(json5 *obj, char *p, char **err_code);\n\nchar *json5__parse_string(json5 *obj, char *p, char **err_code) {\n    assert(obj && p);\n\n    if( *p == '\"' || *p == '\\'' || *p == '`' ) {\n        obj->type = json5_string;\n        obj->string = p + 1;\n\n        char eos_char = *p, *b = obj->string, *e = b;\n        while (*e) {\n            /**/ if( *e == '\\\\' && (e[1] == eos_char) ) ++e;\n            else if( *e == '\\\\' && (e[1] == '\\r' || e[1] == '\\n') ) *e = ' ';\n            else if( *e == eos_char ) break;\n            ++e;\n        }\n\n        *e = '\\0';\n        return p = e + 1;\n    }\n\n    //JSON5_ASSERT; *err_code = \"json5_error_invalid_value\";\n    return NULL;\n}\n\nchar *json5__parse_object(json5 *obj, char *p, char **err_code) {\n    assert(obj && p);\n\n    if( 1 /* *p == '{' */ ) { /* <-- for SJSON */\n        int skip = *p == '{'; /* <-- for SJSON */\n\n        obj->type = json5_object;\n        obj->nodes = 0;\n        obj->count = 0;\n\n        while (*p) {\n            json5 node = { 0 };\n            \n            do { p = json5__trim(p + skip); skip = 1; } while( *p == ',' );\n\n            if( *p == '}' ) {\n                ++p;\n                break;\n            }\n            // @todo: is_unicode() (s[0] == '\\\\' && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]))) {\n            else if( isalpha(*p) || *p == '_' || *p == '$' ) { // also || is_unicode(p)\n                node.name = p;\n\n                do {\n                    ++p;\n                } while (*p && (*p == '_' || isalpha(*p) || isdigit(*p)) ); // also || is_unicode(p)\n\n                char *e = p;\n                p = json5__trim(p);\n                *e = '\\0';\n            }\n            else { //if( *p == '\"' || *p == '\\'' || *p == '`' ) {\n                char *ps = json5__parse_string(&node, p, err_code);\n                if( !ps ) {\n                    return NULL;\n                }\n                p = ps;\n                node.name = node.string;\n                p = json5__trim(p);\n            }\n\n            // @todo: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6\n            if( !(node.name && node.name[0]) ) { // !json5__validate_name(node.name) ) {\n                JSON5_ASSERT; *err_code = \"json5_error_invalid_name\";\n                return NULL;\n            }\n\n            if( !p || (*p && (*p != ':' && *p != '=' /* <-- for SJSON */)) ) {\n                JSON5_ASSERT; *err_code = \"json5_error_invalid_name\";\n                return NULL;\n            }\n            p = json5__trim(p + 1);\n            p = json5__parse_value(&node, p, err_code);\n\n            if( *err_code[0] ) {\n                return NULL;\n            }\n\n            if( node.type != json5_undefined ) {\n                array_push(obj->nodes, node);\n                ++obj->count;\n            }\n\n            if( *p == '}') { ++p; break; }\n        }\n\n        return p;\n    }\n\n    JSON5_ASSERT; *err_code = \"json5_error_invalid_value\";\n    return NULL;\n}\n\nchar *json5__parse_value(json5 *obj, char *p, char **err_code) {\n    assert(obj && p);\n\n    p = json5__trim(p);\n\n    char *is_string = json5__parse_string(obj, p, err_code);\n\n    if( is_string ) {\n        p = is_string;\n        if( *err_code[0] ) {\n            return NULL;\n        }\n    }\n    else if( *p == '{' ) {\n        p = json5__parse_object( obj, p, err_code );\n        if( *err_code[0] ) {\n            return NULL;\n        }\n    }\n    else if( *p == '[' ) {\n        obj->type = json5_array;\n        obj->array = 0;\n        obj->count = 0;\n\n        while (*p) {\n            json5 elem = { 0 };\n\n            do { p = json5__trim(p + 1); } while( *p == ',' );\n            if( *p == ']') { ++p; break; }\n\n            p = json5__parse_value(&elem, p, err_code);\n\n            if( *err_code[0] ) {\n                return NULL;\n            }\n\n            if( elem.type != json5_undefined ) {\n                array_push(obj->array, elem);\n                ++obj->count;\n            }\n            if (*p == ']') { ++p; break; }\n        }\n    }\n    else if( isalpha(*p) || (*p == '-' && !isdigit(p[1])) ) {\n        const char *labels[] = { \"null\", \"on\",\"true\", \"off\",\"false\", \"nan\",\"NaN\", \"-nan\",\"-NaN\", \"inf\",\"Infinity\", \"-inf\",\"-Infinity\" };\n        const int lenghts[] = { 4, 2,4, 3,5, 3,3, 4,4, 3,8, 4,9 };\n        for( int i = 0; labels[i]; ++i ) {\n            if( !strncmp(p, labels[i], lenghts[i] ) ) {\n                p += lenghts[i];\n#ifdef _MSC_VER // somehow, NaN is apparently signed in MSC\n                /**/ if( i >= 5 ) obj->type = json5_real, obj->real = i >= 11 ? -INFINITY : i >= 9 ? INFINITY : i >= 7 ?  NAN :-NAN;\n#else\n                /**/ if( i >= 5 ) obj->type = json5_real, obj->real = i >= 11 ? -INFINITY : i >= 9 ? INFINITY : i >= 7 ? -NAN : NAN;\n#endif\n                else if( i >= 1 ) obj->type = json5_bool, obj->boolean = i <= 2;\n                else              obj->type = json5_null;\n                break;\n            }\n        }\n        if( obj->type == json5_undefined ) {\n            JSON5_ASSERT; *err_code = \"json5_error_invalid_value\";\n            return NULL;\n        }\n    }\n    else if( isdigit(*p) || *p == '+' || *p == '-' || *p == '.' ) {\n        char buffer[32] = {0}, *buf = buffer, is_hex = 0, is_dbl = 0;\n        while( *p && strchr(\"+-.xX0123456789aAbBcCdDeEfF\", *p)) {\n            is_hex |= (*p | 32) == 'x';\n            is_dbl |= *p == '.';\n            *buf++ = *p++;\n        }\n        obj->type = is_dbl ? json5_real : json5_integer;\n        /**/ if( is_dbl ) sscanf( buffer, \"%lf\", &obj->real );\n        else if( is_hex ) sscanf( buffer, \"%llx\", &obj->integer ); // SCNx64 -> inttypes.h\n        else              sscanf( buffer, \"%lld\", &obj->integer ); // SCNd64 -> inttypes.h\n    }\n    else {\n        return NULL;\n    }\n    return p;\n}\n\nchar *json5_parse(json5 *root, char *p, int flags) {\n    char *err_code = \"\";\n    *root = (json5) {0};\n\n    if( p && p[0] ) {\n        p = json5__trim(p);\n        if( *p == '[' ) { /* <-- for SJSON */\n            json5__parse_value(root, p, &err_code);\n        } else {\n            json5__parse_object(root, p, &err_code); /* <-- for SJSON */\n        }\n    } else {\n        root->type = json5_object;\n    }\n\n    return err_code[0] ? err_code : 0;\n}\n\nvoid json5_free(json5 *root) {\n    if( root->type == json5_array && root->array ) {\n        for( int i = 0, cnt = array_count(root->array); i < cnt; ++i ) {\n            json5_free(root->array + i);\n        }\n        array_free(root->array);\n    } \n\n    if( root->type == json5_object && root->nodes ) {\n        for( int i = 0, cnt = array_count(root->nodes); i < cnt; ++i ) {\n            json5_free(root->nodes + i);\n        }\n        array_free(root->nodes);\n    }\n\n    *root = (json5) {0}; // needed?\n}\n\nvoid json5_write(FILE *fp, const json5 *o) {\n#ifdef _MSC_VER\n    static __declspec(thread) int indent = 0;\n#else\n    static __thread int indent = 0;\n#endif\n    int tabs = 1; // 0,1,2,4,8\n    if( o->name ) {\n        fprintf(fp, \"%*.s\\\"%s\\\"%s\", indent * tabs, \"\", o->name, tabs ? \": \" : \":\");\n    }\n    /**/ if( o->type == json5_null ) fprintf(fp, \"%s\", \"null\");\n    else if( o->type == json5_bool ) fprintf(fp, \"%s\", o->boolean ? \"true\" : \"false\");\n    else if( o->type == json5_integer ) fprintf(fp, \"%lld\", o->integer);\n    else if( o->type == json5_real ) {\n        /**/ if( isnan(o->real) ) fprintf(fp, \"%s\", signbit(o->real) ? \"-nan\" : \"nan\" );\n        else if( isinf(o->real) ) fprintf(fp, \"%s\", signbit(o->real) ? \"-inf\" : \"inf\" );\n        else fprintf(fp, \"%1.8e\", o->real); // %1.8e from google:\"randomascii 100 digits\" ; %.4llf for compactness\n    }\n    #if 0\n    else if( o->type == json5_string ) { // write (escaped) string\n        char chars[] = \"\\\\\\\"\\n\\r\\b\\f\\v\", remap[] = \"\\\\\\\"nrbfv\", esc[256];\n        for( int i = 0; chars[i]; ++i ) esc[ chars[i] ] = remap[i];\n\n        const char *b = o->string, *e = strpbrk(b, chars), *sep = \"\\\"\";\n        while( e ) {\n            fprintf(fp, \"%s%.*s\\\\%c\", sep, (int)(e - b), b, esc[(unsigned char)*e] );\n            e = strpbrk( b = e + 1, chars);\n            sep = \"\";\n        }\n        fprintf(fp, \"%s%s\\\"\", sep, b);\n    }\n    #else\n    else if( o->type == json5_string ) { // write string\n        fprintf(fp, \"\\\"%s\\\"\", o->string);\n    }\n    #endif\n    else if( o->type == json5_array ) {\n        const char *sep = \"\";\n        fprintf(fp, \"%s\", tabs ? \"[ \" : \"[\");\n        for( int i = 0, cnt = o->count; i < cnt; ++i ) {\n            fprintf(fp, \"%s\", sep); sep = tabs ? \", \" : \",\";\n            json5_write(fp, o->array + i);\n        }\n        fprintf(fp, \"%s\", tabs ? \" ]\" : \"]\");\n    }\n    else if( o->type == json5_object ) {\n        const char *sep = \"\";\n        fprintf(fp, \"%*.s{%s\", 0 * (++indent) * tabs, \"\", tabs ? \"\\n\":\"\");\n        for( int i = 0, cnt = o->count; i < cnt; ++i ) {\n            fprintf(fp, \"%s\", sep); sep = tabs ? \",\\n\" : \",\";\n            json5_write(fp, o->nodes + i);\n        }\n        fprintf(fp, \"%s%*.s}\", tabs ? \"\\n\":\"\", (--indent) * tabs, \"\");\n    } else {\n        char p[16] = {0};\n        JSON5_ASSERT; /* \"json5_error_invalid_value\"; */\n    }\n}\n\n#endif // JSON5_C\n\n#ifdef JSON5_BENCH\n#include <time.h>\n\nint main() {\n    // https://www.reddit.com/r/datasets/comments/1uyd0t/200000_jeopardy_questions_in_a_json_file/\n    char *content = 0;\n    for( FILE *fp = fopen(\"jeopardy.json\", \"rb\"); fp; fclose(fp), fp = 0 ) {\n        fseek(fp, 0L, SEEK_END);\n        size_t pos = ftell(fp);\n        fseek(fp, 0L, SEEK_SET);\n        content = (char*)malloc( pos + 1 );\n        fread(content, 1, pos, fp);\n        content[pos] = 0;\n    }\n\n    if( content ) {\n        clock_t start = clock();\n        json5 root = {0};\n        char *error = json5_parse(&root, content, 0);\n        clock_t end = clock();\n        double delta = ( end - start ) / (double)CLOCKS_PER_SEC;\n\n        if( !error ) {\n            printf(\"Parsing time: %.3fms\\n\", delta*1000);\n            printf(\"Total nodes: %d\\n\", array_count(root.array));\n            printf(\"Category: %s, air date: %s\\nQuestion: %s\\n\", root.array[0].nodes[0].string,\n                   root.array[0].nodes[1].string,\n                   root.array[0].nodes[2].string);\n        } else {\n            printf(\"Error: %s\\n\", error);\n        }\n\n        json5_free(&root);\n        free(content);\n    }\n}\n#endif\n\n#ifdef JSON5_DEMO\nint main() {\n    char source5[] = \n    \"  // comments\\n\" /* json5 sample */\n    \"  unquoted: 'and you can quote me on that',\\n\"\n    \"  singleQuotes: 'I can use \\\"double quotes\\\" here',\\n\"\n    \"  lineBreaks : \\\"Look, Mom! \\\\\\n\"\n    \"No \\\\n's!\\\",\\n\"\n    \"  hexadecimal: 0x100,\\n\"\n    \"  leadingDecimalPoint: .8675309, andTrailing: 8675309.,\\n\"\n    \"  positiveSign: +1,\\n\"\n    \"  trailingComma: 'in objects', andIn: ['arrays', ],\\n\"\n    \"  \\\"backwardsCompatible\\\": \\\"with JSON\\\",\\n\"\n    \"\"\n    \"  ip = \\\"127.0.0.1\\\"\\n\" /* sjson sample */\n    \"  port = 8888\\n\"\n    \"\"\n    \"  /* comment //nested comment*/\\n\" /* tests */\n    \"  // comment /*nested comment*/\\n\"\n    \"  nil: null,\"\n    \"  \\\"+lšctžýáíé=:\\\": true,,,,\"\n    \"  huge: 2.2239333e5, \"\n    \"  array: [+1,2,-3,4,5],    \"\n    \"  hello: 'world /*comment in string*/ //again', \"\n    \"  abc: 42.67, def: false, \"\n    \"  children : { a: 1, b: 2, },\"\n    \"  invalids : [ nan, NaN, -nan, -NaN, inf, Infinity, -inf, -Infinity ],\"\n    \"\"\n    \"  multiline: `this is\\n\"\n    \"a multiline string\\n\"\n    \"yeah`\"\n    \"}\\n\";\n\n    json5 root = { 0 };\n    char *error = json5_parse(&root, source5, 0);\n    if( error ) {\n        printf(\"Error: %s\\n\", error);\n    } else {\n        json5_write(stdout, &root);\n    }\n    json5_free(&root);\n}\n#endif\n"
  },
  {
    "path": "vault/buf.c",
    "content": "// - rlyeh, public domain\n\n#ifdef BUF_C\n#define ARC4_C\n#define BASE64_C\n#define BASE92_C\n#define COBS_C\n#define CRC_C\n#define ENDIAN_C\n#define INTERLEAVE_C\n#define NETSTRING_C\n#define ZIGZAG_C\n#define PACK_C\n#define HALF_C\n#endif\n\n#include \"os.c\"\n#include \"buf_arc4.c\"        // buffer_crypt_arc4\n#include \"buf_base64.c\"      // buffer_rebase_base64\n#include \"buf_base92.c\"      // buffer_rebase_base92\n#include \"buf_cobs.c\"        // buffer_rebase_cobs\n#include \"buf_crc.c\"         // buffer_checksum_crc\n#include \"buf_endian.c\"      // buffer_utils_endianness\n#include \"buf_interleave.c\"  // buffer_utils_interleave\n#include \"buf_netstring.c\"   // buffer_escape_netstring\n#include \"buf_zigzag.c\"      // buffer_utils_zigzag\n\n#include \"buf_packint.h\"     // integer packing\n#include \"buf_packvli.h\"     // variable int packing\n#include \"buf_pack754.h\"     // float754 packing\n#include \"buf_packhalf.h\"    // floathalf packing\n#include \"buf_pack.c\"        // data packer\n"
  },
  {
    "path": "vault/buf_arc4.c",
    "content": "// ARC4 de/cryptor. Based on code by Mike Shaffer.\n// - rlyeh, public domain.\n\nvoid *arc4( void *buffer, unsigned buflen, const void *pass, unsigned passlen );\n\n#ifdef ARC4_C\n#pragma once\n#include <assert.h>\n\nvoid *arc4( void *buf_, unsigned buflen, const void *pass_, unsigned passlen ) {\n    // [ref] http://www.4guysfromrolla.com/webtech/code/rc4.inc.html\n    assert(passlen);\n    int sbox[256], key[256];\n    char *buf = (char*)buf_;\n    const char *pass = (const char*)pass_;\n    for( unsigned a = 0; a < 256; a++ ) {\n        key[a] = pass[a % passlen];\n        sbox[a] = a;\n    }\n    for( unsigned a = 0, b = 0; a < 256; a++ ) {\n        b = (b + sbox[a] + key[a]) % 256;\n        int swap = sbox[a]; sbox[a] = sbox[b]; sbox[b] = swap;\n    }\n    for( unsigned a = 0, b = 0, i = 0; i < buflen; ++i ) {\n        a = (a + 1) % 256;\n        b = (b + sbox[a]) % 256;\n        int swap = sbox[a]; sbox[a] = sbox[b]; sbox[b] = swap;\n        buf[i] ^= sbox[(sbox[a] + sbox[b]) % 256];\n    }\n    return buf_;\n}\n\n#ifdef ARC4_DEMO\n#include <stdio.h>\n#include <string.h>\nint main( int argc, char **argv ) {\n    char buffer[] = \"Hello world.\"; int buflen = strlen(buffer);\n    char *password = argc > 1 ? argv[1] : \"abc123\"; int passlen = strlen(password);\n\n    printf(\"Original: %s\\n\", buffer);\n    printf(\"Password: %s\\n\", password);\n\n    char *encrypted = arc4( buffer, buflen, password, passlen );\n    printf(\"ARC4 Encrypted text: '%s'\\n\", encrypted);\n\n    char *decrypted = arc4( buffer, buflen, password, passlen );\n    printf(\"ARC4 Decrypted text: '%s'\\n\", decrypted);\n}\n#endif // ARC4_DEMO\n#endif // ARC4_C\n"
  },
  {
    "path": "vault/buf_base64.c",
    "content": "// base64 de/encoder. Based on code by Jon Mayo - November 13, 2003 (PUBLIC DOMAIN).\n// - rlyeh, public domain\n//\n// note: functions return 0 on error\n// note: base64(\"\")==\"\"\n\n#ifndef BASE64_H\n#define BASE64_H\n\nunsigned base64_bounds(unsigned inlen);\nunsigned base64_encode(const void *in, unsigned inlen, void *out, unsigned outlen);\nunsigned base64_decode(const void *in, unsigned inlen, void *out, unsigned outlen);\n\n#endif\n\n#ifdef BASE64_C\n#pragma once\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <ctype.h>\n\nunsigned base64_bounds(unsigned size) {\n    return 4 * ((size + 2) / 3);\n}\n\nunsigned base64_encode(const void *in_, unsigned inlen, void *out_, unsigned outlen) {\n    uint_least32_t v;\n    unsigned ii, io, rem;\n    char *out = (char *)out_;\n    const unsigned char *in = (const unsigned char *)in_;\n    const uint8_t base64enc_tab[]= \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\n\n    for(io = 0, ii = 0, v = 0, rem = 0; ii < inlen; ii ++) {\n        unsigned char ch;\n        ch = in[ii];\n        v = (v << 8) | ch;\n        rem += 8;\n        while (rem >= 6) {\n            rem -= 6;\n            if (io >= outlen)\n                return 0; /* truncation is failure */\n            out[io ++] = base64enc_tab[(v >> rem) & 63];\n        }\n    }\n    if (rem) {\n        v <<= (6 - rem);\n        if (io >= outlen)\n            return 0; /* truncation is failure */\n        out[io ++] = base64enc_tab[v & 63];\n    }\n    if (io < outlen)\n        out[io] = 0;\n\n    return io;\n}\n\nunsigned base64_decode(const void *in_, unsigned inlen, void *out_, unsigned outlen) {\n    uint_least32_t v;\n    unsigned ii, io, rem;\n    char *out = (char *)out_;\n    const unsigned char *in = (const unsigned char *)in_;\n    const uint8_t base64dec_tab[256]= {\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255, 62,255,255,\n         52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,  0,255,255,\n        255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,\n         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255, 63,\n        255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,\n         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n        255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,\n    };\n\n    for (io = 0, ii = 0,v = 0, rem = 0; ii < inlen; ii ++) {\n        unsigned char ch;\n        if (isspace(in[ii]))\n            continue;\n        if ((in[ii]=='=') || (!in[ii]))\n            break; /* stop at = or null character*/\n        ch = base64dec_tab[(unsigned char)in[ii]];\n        if (ch == 255)\n            break; /* stop at a parse error */\n        v = (v<<6) | ch;\n        rem += 6;\n        if (rem >= 8) {\n            rem -= 8;\n            if (io >= outlen)\n                return 0; /* truncation is failure */\n            out[io ++] = (v >> rem) & 255;\n        }\n    }\n    if (rem >= 8) {\n        rem -= 8;\n        if (io >= outlen)\n            return 0; /* truncation is failure */\n        out[io ++] = (v >> rem) & 255;\n    }\n    return io;\n}\n\n#endif // BASE64_C\n"
  },
  {
    "path": "vault/buf_base92.c",
    "content": "// THE BEERWARE LICENSE (Revision 42):\n// <thenoviceoof> wrote this file. As long as you retain this notice you\n// can do whatever you want with this stuff. If we meet some day, and you\n// think this stuff is worth it, you can buy me a beer in return\n// - Nathan Hwang (thenoviceoof)\n\n#ifndef BASE92_H\n#define BASE92_H\n\nunsigned base92_encode(const void *in, unsigned inlen, void* out, unsigned outlen);\nunsigned base92_decode(const void *in, unsigned inlen, void* out, unsigned outlen);\nunsigned base92_bounds(unsigned inlen);\n\n#endif\n\n#ifdef BASE92_C\n#pragma once\n#include <stdlib.h>\n#include <string.h>\n\nunsigned base92_bounds(unsigned inlen) {\n    unsigned size = (inlen * 8) % 13, extra_null = 1;\n    if(size == 0) return 2 * ((inlen * 8) / 13) + extra_null;\n    if(size  < 7) return 2 * ((inlen * 8) / 13) + extra_null + 1;\n                  return 2 * ((inlen * 8) / 13) + extra_null + 2;\n}\n\nunsigned base92_encode(const void* in, unsigned inlen, void *out, unsigned size) {\n    char *res = (char *)out;\n    const unsigned char *str = (const unsigned char *)in;\n    unsigned int j = 0;          // j for encoded\n    unsigned long workspace = 0; // bits holding bin\n    unsigned short wssize = 0;   // number of good bits in workspace\n    unsigned char c;\n    const unsigned char ENCODE_MAPPING[256] = {\n        33, 35, 36, 37, 38, 39, 40, 41, 42, 43,\n        44, 45, 46, 47, 48, 49, 50, 51, 52, 53,\n        54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n        64, 65, 66, 67, 68, 69, 70, 71, 72, 73,\n        74, 75, 76, 77, 78, 79, 80, 81, 82, 83,\n        84, 85, 86, 87, 88, 89, 90, 91, 92, 93,\n        94, 95, 97, 98, 99, 100, 101, 102, 103, 104,\n        105, 106, 107, 108, 109, 110, 111, 112, 113, 114,\n        115, 116, 117, 118, 119, 120, 121, 122, 123, 124,\n        125, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0\n    };\n    if (inlen) {\n        for (unsigned i = 0; i < inlen; i++) {\n            workspace = workspace << 8 | str[i];\n            wssize += 8;\n            if (wssize >= 13) {\n                int tmp = (workspace >> (wssize - 13)) & 8191;\n                c = ENCODE_MAPPING[(tmp / 91)];\n                if (c == 0) return 0; // illegal char\n                res[j++] = c;\n                c = ENCODE_MAPPING[(tmp % 91)];\n                if (c == 0) return 0; // illegal char\n                res[j++] = c;\n                wssize -= 13;\n            }\n        }\n        // encode a last byte\n        if (0 < wssize && wssize < 7) {\n            int tmp = (workspace << (6 - wssize)) & 63;  // pad the right side\n            c = ENCODE_MAPPING[(tmp)];\n            if (c == 0) return 0; // illegal char\n            res[j++] = c;\n        } else if (7 <= wssize) {\n            int tmp = (workspace << (13 - wssize)) & 8191; // pad the right side\n            c = ENCODE_MAPPING[(tmp / 91)];\n            if (c == 0) return 0; // illegal char\n            res[j++] = c;\n            c = ENCODE_MAPPING[(tmp % 91)];\n            if (c == 0) return 0; // illegal char\n            res[j++] = c;\n        }\n    } else {\n        res[j++] = '~';\n    }\n    // add null byte\n    res[j] = 0;\n    return j;\n}\n\n// this guy expects a null-terminated string\n// gives back a non-null terminated string, and properly filled len\nunsigned base92_decode(const void* in, unsigned size, void *out, unsigned outlen_unused) {\n    const char* str = (const char*)in;\n    unsigned char *res = (unsigned char *)out;\n    int i, j = 0, b1, b2;\n    unsigned long workspace = 0;\n    unsigned short wssize = 0;\n    const unsigned char DECODE_MAPPING[256] = {\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 0, 255, 1, 2, 3, 4, 5,\n        6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n        16, 17, 18, 19, 20, 21, 22, 23, 24, 25,\n        26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\n        36, 37, 38, 39, 40, 41, 42, 43, 44, 45,\n        46, 47, 48, 49, 50, 51, 52, 53, 54, 55,\n        56, 57, 58, 59, 60, 61, 255, 62, 63, 64,\n        65, 66, 67, 68, 69, 70, 71, 72, 73, 74,\n        75, 76, 77, 78, 79, 80, 81, 82, 83, 84,\n        85, 86, 87, 88, 89, 90, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n        255, 255, 255, 255, 255, 255\n    };\n\n    // handle small cases first\n    if (size == 0 || (str[0] == '~' && str[1] == '\\0')) {\n        res[0] = 0;\n        return 1;\n    }\n    // calculate size\n    int len = ((size/2 * 13) + (size%2 * 6)) / 8;\n    // handle pairs of chars\n    for (i = 0; i + 1 < size; i += 2) {\n        b1 = DECODE_MAPPING[(str[i])];\n        b2 = DECODE_MAPPING[(str[i+1])];\n        workspace = (workspace << 13) | (b1 * 91 + b2);\n        wssize += 13;\n        while (wssize >= 8) {\n            res[j++] = (workspace >> (wssize - 8)) & 255;\n            wssize -= 8;\n        }\n    }\n    // handle single char\n    if (size % 2 == 1) {\n        workspace = (workspace << 6) | DECODE_MAPPING[(str[size - 1])];\n        wssize += 6;\n        while (wssize >= 8) {\n            res[j++] = (workspace >> (wssize - 8)) & 255;\n            wssize -= 8;\n        }\n    }\n    //assert(j == len);\n    return j;\n}\n\n#endif\n"
  },
  {
    "path": "vault/buf_cobs.c",
    "content": "// Based on code by Jacques Fortier.\n// \"Redistribution and use in source and binary forms are permitted, with or without modification.\"\n//\n// Consistent Overhead Byte Stuffing is an encoding that removes all 0 bytes from arbitrary binary data.\n// The encoded data consists only of bytes with values from 0x01 to 0xFF. This is useful for preparing data for\n// transmission over a serial link (RS-232 or RS-485 for example), as the 0 byte can be used to unambiguously indicate\n// packet boundaries. COBS also has the advantage of adding very little overhead (at least 1 byte, plus up to an\n// additional byte per 254 bytes of data). For messages smaller than 254 bytes, the overhead is constant.\n// \n// This implementation is designed to be both efficient and robust. \n// The decoder is designed to detect malformed input data and report an error upon detection.\n//\n\n#ifndef COBS_H\n#define COBS_H\n\nunsigned cobs_bounds(unsigned len);\nunsigned cobs_encode(const void *in, unsigned inlen, void *out, unsigned outlen);\nunsigned cobs_decode(const void *in, unsigned inlen, void *out, unsigned outlen);\n\n#endif\n\n#ifdef COBS_C\n#pragma once\n#include <stdint.h>\n#include <stddef.h>\n#include <math.h>\n\nunsigned cobs_bounds( unsigned len ) {\n    return ceil(len / 254.0) + 1;\n}\nunsigned cobs_encode(const void *in, unsigned inlen, void *out, unsigned outlen) {\n    const uint8_t *src = (const uint8_t *)in;\n    uint8_t *dst = (uint8_t*)out;\n    size_t srclen = inlen;\n\n    uint8_t code = 1;\n    size_t read_index = 0, write_index = 1, code_index = 0;\n\n    while( read_index < srclen ) {\n        if( src[ read_index ] == 0) {\n            dst[ code_index ] = code;\n            code = 1;\n            code_index = write_index++;\n            read_index++;\n        } else {\n            dst[ write_index++ ] = src[ read_index++ ];\n            code++;\n            if( code == 0xFF ) {\n                dst[ code_index ] = code;\n                code = 1;\n                code_index = write_index++;\n            }\n        }\n    }\n\n    dst[ code_index ] = code;\n    return write_index;\n}\nunsigned cobs_decode(const void *in, unsigned inlen, void *out, unsigned outlen) {\n    const uint8_t *src = (const uint8_t *)in;\n    uint8_t *dst = (uint8_t*)out;\n    size_t srclen = inlen;\n\n    uint8_t code, i;\n    size_t read_index = 0, write_index = 0;\n\n    while( read_index < srclen ) {\n        code = src[ read_index ];\n\n        if( ((read_index + code) > srclen) && (code != 1) ) {\n            return 0;\n        }\n\n        read_index++;\n\n        for( i = 1; i < code; i++ ) {\n            dst[ write_index++ ] = src[ read_index++ ];\n        }\n        if( (code != 0xFF) && (read_index != srclen) ) {\n            dst[ write_index++ ] = '\\0';\n        }\n    }\n\n    return write_index;\n}\n\n#ifdef COBS_DEMO\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\nvoid test( const char *buffer, int buflen ) {\n    char enc[4096];\n    int enclen = cobs_encode( buffer, buflen, enc, 4096 );\n\n    char dec[4096];\n    int declen = cobs_decode( enc, enclen, dec, 4096 );\n\n    assert( enclen >= buflen );\n    assert( declen == buflen );\n    assert( memcmp(dec, buffer, buflen) == 0 );\n\n    printf(\"%d->%d->%d (+%d extra bytes)\\n\", declen, enclen, declen, enclen - declen);\n}\nint main() {\n    const char *null = 0;\n    test( null, 0 );\n\n    const char empty[] = \"\";\n    test( empty, sizeof(empty) );\n\n    const char text[] = \"hello world\\n\";\n    test( text, sizeof(text) );\n\n    const char bintext[] = \"hello\\0\\0\\0world\\n\";\n    test( bintext, sizeof(bintext) );\n\n    const char blank[512] = {0};\n    test( blank, sizeof(blank) );\n\n    char longbintext[1024];\n    for( int i = 0; i < 1024; ++i ) longbintext[i] = (unsigned char)i;\n    test( longbintext, sizeof(longbintext) );\n\n    assert(~puts(\"Ok\"));\n}\n#define main main__\n#endif // COBS_DEMO\n#endif // COBS_C\n"
  },
  {
    "path": "vault/buf_crc.c",
    "content": "// - rlyeh, public domain\n\nunsigned crc32(unsigned h, const void *ptr, unsigned len);\nuint64_t crc64(uint64_t h, const void *ptr, uint64_t len);\n\n#ifdef CRC_C\n#pragma once\n\nunsigned crc32(unsigned h, const void *ptr_, unsigned len) {\n    // based on public domain code by Karl Malbrain\n    const uint8_t *ptr = (const uint8_t *)ptr_;\n    if (!ptr) return 0;\n    const unsigned tbl[16] = {\n        0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,\n        0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };\n    for(h = ~h; len--; ) { uint8_t b = *ptr++; h = (h >> 4) ^ tbl[(h & 15) ^ (b & 15)]; h = (h >> 4) ^ tbl[(h & 15) ^ (b >> 4)]; }\n    return ~h;\n}\n\nuint64_t crc64(uint64_t h, const void *ptr, uint64_t len) {\n    // based on public domain code by Lasse Collin\n    // also, use poly64 0xC96C5795D7870F42 for crc64-ecma\n    static uint64_t crc64_table[256];\n    static uint64_t poly64 = UINT64_C(0x95AC9329AC4BC9B5);\n    if( poly64 ) {\n        for( int b = 0; b < 256; ++b ) {\n            uint64_t r = b;\n            for( int i = 0; i < 8; ++i ) {\n                r = r & 1 ? (r >> 1) ^ poly64 : r >> 1;\n            }\n            crc64_table[ b ] = r;\n            //printf(\"%016llx\\n\", crc64_table[b]);\n        }\n        poly64 = 0;\n    }\n    const uint8_t *buf = (const uint8_t *)ptr;\n    uint64_t crc = ~h; // ~crc;\n    while( len != 0 ) {\n        crc = crc64_table[(uint8_t)crc ^ *buf++] ^ (crc >> 8);\n        --len;\n    }\n    return ~crc;\n}\n#endif\n"
  },
  {
    "path": "vault/buf_endian.c",
    "content": "// binary endianness ----------------------------------------------------------\n// - rlyeh, public domain\n\n#pragma once\n#include <stdint.h>\n\nstatic uint16_t bswap16( uint16_t x ) {\n    return (x << 8) | (x >> 8);\n}\nstatic uint32_t bswap32( uint32_t x ) { \n    x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);\n    return (x << 16) | (x >> 16);\n}\nstatic uint64_t bswap64( uint64_t x ) { \n    x = ((x <<  8) & 0xff00ff00ff00ff00ULL) | ((x >>  8) & 0x00ff00ff00ff00ffULL);\n    x = ((x << 16) & 0xffff0000ffff0000ULL) | ((x >> 16) & 0x0000ffff0000ffffULL);\n    return (x << 32) | (x >> 32);\n}\nstatic int is_big() {\n    return (*(uint16_t *)\"\\0\\1\") == 1;\n}\nstatic int is_little() {\n    return (*(uint16_t *)\"\\0\\1\") != 1;\n}\n\n#if defined(_MSC_VER)\n#include <stdlib.h>\n#define bswap16 _byteswap_ushort\n#define bswap32 _byteswap_ulong\n#define bswap64 _byteswap_uint64\n#elif defined __GNUC__\n#define bswap16 __builtin_bswap16\n#define bswap32 __builtin_bswap32\n#define bswap64 __builtin_bswap64\n#endif\n"
  },
  {
    "path": "vault/buf_interleave.c",
    "content": "// array de/interleaving\n// - rlyeh, public domain.\n//\n// results:\n// R0G0B0   R1G1B1   R2G2B2...   -> R0R1R2... B0B1B2... G0G1G2...\n// R0G0B0A0 R1G1B1A1 R2G2B2A2... -> R0R1R2... A0A1A2... B0B1B2... G0G1G2...\n\n#ifndef INTERLEAVE_H\n#define INTERLEAVE_H\n\nvoid *interleave( void *out, const void *list, int list_count, int sizeof_item, unsigned columns );\n\n#endif\n\n// -----------------------------------------------------------------------------\n\n#ifdef INTERLEAVE_C\n#pragma once\n#include <assert.h>\n#include <string.h>\n\nvoid *interleave( void *out, const void *list, int list_count, int sizeof_item, unsigned columns ) {\n    void *bak = out;\n    assert( columns < list_count ); // required\n    int row_count = list_count / columns;\n    for( int offset = 0; offset < columns; offset++ ) {\n        for( int row = 0; row < row_count; row++ ) {\n            memcpy( out, &((char*)list)[ (offset + row * columns) * sizeof_item ], sizeof_item );\n            out = ((char*)out) + sizeof_item;\n        }\n    }\n    return bak;\n}\n\n#ifdef INTERLEAVE_DEMO\n#include <stdio.h>\nvoid test( const char *name, int interleaving, int deinterleaving, const char *original ) {\n    char interleaved[128] = {0};\n    interleave( interleaved, original, strlen(original)/2, 2, interleaving );\n    char deinterleaved[128] = {0};\n    interleave( deinterleaved, interleaved, strlen(original)/2, 2, deinterleaving );\n\n    printf( \"\\n%s\\n\", name );\n    printf( \"original:\\t%s\\n\", original );\n    printf( \"interleaved:\\t%s\\n\", interleaved );\n    printf( \"deinterleaved:\\t%s\\n\", deinterleaved );\n\n    assert( 0 == strcmp(original, deinterleaved) );\n}\nint main() {\n    test(\"audio 2ch\", 2, 3,\n        \"L0R0\"\n        \"L1R1\"\n        \"L2R2\"\n    );\n    test(\"image 3ch\", 3, 3,\n        \"R0G0B0\"\n        \"R1G1B1\"\n        \"R2G2B2\"\n    );\n    test(\"image 4ch\", 4, 3,\n        \"R0G0B0A0\"\n        \"R1G1B1A1\"\n        \"R2G2B2A2\"\n    );\n    test(\"audio 5ch\", 5, 3,\n        \"A0B0C0L0R0\"\n        \"A1B1C1L1R1\"\n        \"A2B2C2L2R2\"\n    );\n    test(\"audio 5.1ch\", 6, 3,\n        \"A0B0C0L0R0S0\"\n        \"A1B1C1L1R1S1\"\n        \"A2B2C2L2R2S2\"\n    );\n    test(\"opengl material 9ch\", 9, 3,\n        \"X0Y0Z0q0w0e0r0u0v0\"\n        \"X1Y1Z1q1w1e1r1u1v1\"\n        \"X2Y2Z2q2w2e2r2u2v2\"\n    );\n    test(\"opengl material 10ch\", 10, 3,\n        \"X0Y0Z0q0w0e0r0s0u0v0\"\n        \"X1Y1Z1q1w1e1r1s1u1v1\"\n        \"X2Y2Z2q2w2e2r2s2u2v2\"\n    );\n    assert(~puts(\"Ok\"));\n}\n#endif // INTERLEAVE_DEMO\n#endif // INTERLEAVE_C\n"
  },
  {
    "path": "vault/buf_netstring.c",
    "content": "// netstring en/decoder\n// - rlyeh, public domain.\n\nunsigned netstring_bounds(unsigned inlen);\nunsigned netstring_encode(const char *in, unsigned inlen, char *out, unsigned outlen);\nunsigned netstring_decode(const char *in, unsigned inlen, char *out, unsigned outlen);\n\n#ifdef NETSTRING_C\n#pragma once\n#include <stdio.h>\n#include <string.h>\n\nunsigned netstring_bounds(unsigned inlen) {\n    return 5 + inlen + 3; // 3 for ;,\\0 + 5 if inlen < 100k ; else (unsigned)ceil(log10(inlen + 1))\n}\nunsigned netstring_encode(const char *in, unsigned inlen, char *out, unsigned outlen) {\n//  if(outlen < netstring_bounds(inlen)) return 0;\n    sprintf(out, \"%u:%.*s,\", inlen, inlen, in);\n    return strlen(out);\n}\nunsigned netstring_decode(const char *in, unsigned inlen, char *out, unsigned outlen) {\n//  if(outlen < inlen) return 0;\n    const char *bak = in;\n    sscanf(in, \"%u\", &outlen);\n    while( *++in != ':' );\n    memcpy(out, in+1, outlen), out[outlen-1] = 0;\n    // return outlen; // number of written bytes\n    return (outlen + (in+2 - bak)); // number of read bytes\n}\n\n#ifdef NETSTRING_DEMO\n#include <stdlib.h>\nint main() {\n    // encode\n    const char text1[] = \"hello world!\", text2[] = \"abc123\";\n    unsigned buflen = netstring_bounds(strlen(text1) + strlen(text2));\n    char *buf = malloc(buflen), *ptr = buf;\n    ptr += netstring_encode(text1, strlen(text1), ptr, buflen -= (ptr - buf));\n    ptr += netstring_encode(text2, strlen(text2), ptr, buflen -= (ptr - buf));\n    printf(\"%s -> \", buf);\n\n    // decode\n    char out[12];\n    unsigned plen = strlen(ptr = buf);\n    while(plen > 0) {\n        int written = netstring_decode(ptr, plen, out, 12);\n        ptr += written;\n        plen -= written;\n        printf(\"'%s'(%s)(%d), \", out, ptr, plen );\n    }\n    puts(\"\");\n}\n#define main main__\n#endif // NETSTRING_DEMO\n#endif // NETSTRING_C\n"
  },
  {
    "path": "vault/buf_pack.c",
    "content": "// Based on code by Brian \"Beej Jorgensen\" Hall (public domain) [1].\n// Based on code by Ginger Bill's half<->float (public domain) [2].\n// - rlyeh, public domain.\n//\n// pack.c  -- perl/python-ish pack/unpack functions\n// like printf and scanf, but for binary data.\n//\n// format flags:\n//  (<) little endian       (>) big endian (! also)     (=) native endian\n//  (c) 8-bit  char         (b) 8-bit  byte\n//  (h) 16-bit half         (w) 16-bit word\n//  (i) 32-bit integer      (u) 32-bit unsigned         (f) 32-bit float\n//  (l) 64-bit long         (q) 64-bit quad             (d) 64-bit double\n//  (v) varint\n//  (s) string   (64-bit varint length prepended)\n//  (S) string   (32-bit fixed  length prepended)\n//  (m) memblock (64-bit varint length prepended)\n//  (M) memblock (32-bit fixed  length prepended)\n//  (z) memblock (zeroed)\n//  (#) number of arguments processed (only when unpacking)\n//\n// @todo:\n// - (x) document & test flag\n// @totest:\n// - (s) string   (64-bit variable length automatically prepended)\n// - (S) string   (32-bit fixed    length automatically prepended)\n// - (m) memblock (64-bit variable length automatically prepended)\n// - (M) memblock (32-bit fixed    length automatically prepended)\n// - (z) memblock (zeroed)\n// - (#) number of arguments processed (only when unpacking)\n//\n// @refs:\n// [1] http://beej.us/guide/bgnet/output/html/multipage/advanced.html#serialization (Modified to encode NaN and Infinity as well.)\n// [2] https://github.com/gingerBill/gb\n// [3] http://www.mrob.com/pub/math/floatformats.html#minifloat\n// [4] microfloat: [0.002 to 240] range.\n// [5] half float: can approximate any 16-bit unsigned integer or its reciprocal to 3 decimal places.\n\n#ifndef PACK_H\n#define PACK_H\n#include <stdio.h>\n#include <stdarg.h>\n#include <stdint.h>\n\n// - save data dictated by the format string from the buffer. return: number of bytes written, or 0 if error.\n//   if first argument is zero, returns number of bytes required for packing.\n\nint savef(FILE *file, const char *format, ...);\nint saveb(unsigned char *buf, const char *format, ...);\n\n// - load data dictated by the format string into the buffer. return: number of bytes read, or 0 if error.\n//   if first argument is zero, returns number of bytes required for unpacking.\n\nint loadf(FILE *file, const char *format, ...);\nint loadb(const unsigned char *buf, const char *format, ...);\n\n#endif\n\n\n#ifdef PACK_C\n#pragma once\n\n// #include \"packendian.c\" // endianness\n// #include \"pack754.c\" // float754 packing --------------------------------------\n// #include \"packint.c\" // integer packing ---------------------------------------\n// #include \"packvli.c\" // variable int packing ----------------------------------\n\n// b/f packing -----------------------------------------------------------------\n\n#include <ctype.h>\n#include <inttypes.h>\n#include <math.h>\n#include <stdarg.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\nint loadb_(const uint8_t *buf, const char *fmt, va_list ap) {\n    uint64_t args = 0;\n    const uint8_t *buf0 = buf;\n    char tmp[16+1];\n    //uint64_t size = 0, len;\n    int32_t len, count, maxstrlen=0;\n    int le = 0;\n\n    if(!buf) // buffer estimation\n    for(; *fmt != '\\0'; fmt++) {\n        switch(*fmt) {\n        default: if (!isdigit(*fmt)) return 0;\n        break; case '!': case '>': case '<': case '=': case ' ':                                                      //  0-bit endianness\n        break; case 'c': case 'b': { int8_t c = (int8_t)va_arg(ap, int); buf += 1; }                                  //  8-bit promoted\n        break; case 'h': case 'w': { int16_t h = (int16_t)va_arg(ap, int); buf += 2; }                                // 16-bit promoted\n        break; case 'i': case 'u': { int32_t l = va_arg(ap, int32_t); buf += 4; }                                     // 32-bit\n        break; case 'l': case 'q': { int64_t L = va_arg(ap, int64_t); buf += 8; }                                     // 64-bit\n        break; case 'f': { float f = (float)va_arg(ap, double); buf += 4; }                                           // 32-bit float promoted\n        break; case 'd': { double F = (double)va_arg(ap, double); buf += 8; }                                         // 64-bit float (double)\n        break; case 'v': { int64_t L = va_arg(ap, int64_t); buf += pack64iv(tmp, L); }                                // varint (8,16,32,64 ...)\n        break; case 's': { char* s = va_arg(ap, char*); len = strlen(s); buf += pack64iv(tmp, len) + len; }           // string, 64-bit variable length prepended\n        break; case 'S': { char* s = va_arg(ap, char*); len = strlen(s); buf += 4 + len; }                            // string, 32-bit fixed    length prepended\n        break; case 'm': { int len = va_arg(ap, int); char *s = va_arg(ap, char*); buf += pack64iv(tmp, len) + len; } // memblock, 64-bit variable length prepended\n        break; case 'M': { int len = va_arg(ap, int); char *s = va_arg(ap, char*); buf += 4 + len; }                  // memblock, 32-bit fixed    length prepended\n        break; case 'z': { int len = va_arg(ap, int); buf += len; }                                                   // memblock (zeroed)\n        }\n    }\n\n    if(buf) // buffer unpacking\n    for(; *fmt != '\\0'; fmt++) {\n        switch(*fmt) {\n        default:\n            if (isdigit(*fmt)) { // track max str len\n                maxstrlen = maxstrlen * 10 + (*fmt-'0');\n            } else {\n                return 0;\n            }\n        break; case ' ':\n        break; case '!': le = 0;\n        break; case '>': le = 0;\n        break; case '<': le = 1;\n        break; case '=': le = is_little() ? 1 : 0;\n        break; case 'c': case 'b': ++args; { // 8-bit\n            int8_t *v = va_arg(ap, int8_t*);\n            *v = *buf <= 0x7f ? (int8_t)*buf : -1 -(uint8_t)(0xffu - *buf);\n            buf += 1;\n        }\n        break; case 'h': case 'w': ++args; { // 16-bit\n            int16_t *v = va_arg(ap, int16_t*);\n            *v = unpack16i(buf, le);\n            buf += 2;\n        }\n        break; case 'i': case 'u': ++args; { // 32-bit\n            int32_t *v = va_arg(ap, int32_t*);\n            *v = unpack32i(buf, le);\n            buf += 4;\n        }\n        break; case 'l': case 'q': ++args; { // 64-bit\n            int64_t *v = va_arg(ap, int64_t*);\n            *v = unpack64i(buf, le);\n            buf += 8;\n        }\n        break; case 'v': ++args; { // varint (8,16,32,64 ...)\n            int64_t *L = va_arg(ap, int64_t*);\n            buf += unpack64iv(buf, L);\n        }\n        break; case 'f': ++args; { // 32-bit float\n            float *v = va_arg(ap, float*);\n            int32_t i = unpack32i(buf, le);\n            *v = unpack754_32(i);\n            buf += 4;\n        }\n        break; case 'd': ++args; { // 64-bit float (double)\n            double *v = va_arg(ap, double*);\n            int64_t i = unpack64i(buf, le);\n            *v = unpack754_64(i);\n            buf += 8;\n        }\n        break; case 'S': ++args; { // string, 32-bit fixed length prepended\n            char *s = va_arg(ap, char*);\n            int64_t vlen = unpack32i(buf, le), read = 4;\n            count = (maxstrlen > 0 && vlen >= maxstrlen ? maxstrlen - 1 : vlen);\n            memcpy(s, buf + read, count);\n            s[count] = '\\0';\n            buf += read + vlen;\n        }\n        break; case 's': ++args; { // string, 64-bit variable length prepended\n            char *s = va_arg(ap, char*);\n            int64_t vlen, read = unpack64iv(buf, &vlen);\n            count = (maxstrlen > 0 && vlen >= maxstrlen ? maxstrlen - 1 : vlen);\n            memcpy(s, buf + read, count);\n            s[count] = '\\0';\n            buf += read + vlen;\n        }\n        break; case 'M': ++args; { // memblock, 32-bit fixed length prepended\n            char *s = va_arg(ap, char*);\n            int64_t vlen = unpack64iv(buf, &vlen), read = 4;\n            count = vlen; //(maxstrlen > 0 && vlen >= maxstrlen ? maxstrlen - 1 : vlen);\n            memcpy(s, buf + read, count);\n            //s[count] = '\\0';\n            buf += read + vlen;\n        }\n        break; case 'm': ++args; { // memblock, 64-bit variable length prepended\n            char *s = va_arg(ap, char*);\n            int64_t vlen, read = unpack64iv(buf, &vlen);\n            count = vlen; //(maxstrlen > 0 && vlen >= maxstrlen ? maxstrlen - 1 : vlen);\n            memcpy(s, buf + read, count);\n            //s[count] = '\\0';\n            buf += read + vlen;\n        }\n        break; case 'z': ++args; { // zero-init mem block\n            int *l = va_arg(ap, int*);\n            const uint8_t *prev = buf;\n            while( *buf == 0 ) ++buf;\n            *l = buf - prev;\n        }\n        break; case '#': {\n            int *l = va_arg(ap, int*);\n            *l = args;\n        }\n        }\n\n        if (!isdigit(*fmt)) {\n            maxstrlen = 0;\n        }\n    }\n\n    return (int)( buf - buf0 );\n}\n\nint saveb_(uint8_t *buf, const char *fmt, va_list ap) {\n    uint64_t size = 0, len;\n    int le = 0;\n\n    // buffer estimation\n    if( !buf ) {\n        return loadb_(buf, fmt, ap); // + strlen(buf) * 17; // worse (v)arint estimation for 128-bit ints (17 bytes each)\n    }\n\n    // buffer packing\n    for(; *fmt != '\\0'; fmt++) {\n        switch(*fmt) {\n        default: size = 0; // error\n        break; case '!': le = 0; \n        break; case '>': le = 0; \n        break; case '<': le = 1; \n        break; case ' ': le = le; \n        break; case '=': le = is_little() ? 1 : 0;\n        break; case 'c': case 'b': { // 8-bit\n            int v = (int8_t)va_arg(ap, int /*promoted*/ );\n            *buf++ = (v>>0)&0xff;\n            size += 1;\n        }\n        break; case 'h': case 'w': { // 16-bit\n            int v = (int16_t)va_arg(ap, int /*promoted*/ );\n            pack16i(buf, v, le);\n            buf += 2;\n            size += 2;\n        }\n        break; case 'i': case 'u': { // 32-bit\n            int32_t v = va_arg(ap, int32_t);\n            pack32i(buf, v, le);\n            buf += 4;\n            size += 4;\n        }\n        break; case 'l': case 'q': { // 64-bit\n            int64_t v = va_arg(ap, int64_t);\n            pack64i(buf, v, le);\n            buf += 8;\n            size += 8;\n        }\n        break; case 'v': { // varint (8,16,32,64 ...)\n            int64_t v = va_arg(ap, int64_t);\n            int64_t L = pack64iv(buf, v);\n            buf += L;\n            size += L;\n        }\n        break; case 'f': { // 32-bit float\n            double v = (float)va_arg(ap, double /*promoted*/ );\n            int32_t i = pack754_32(v); // convert to IEEE 754\n            pack32i(buf, i, le);\n            buf += 4;\n            size += 4;\n        }\n        break; case 'd': { // 64-bit float (double)\n            double v = (double)va_arg(ap, double);\n            int64_t i = pack754_64(v); // convert to IEEE 754\n            pack64i(buf, i, le);\n            buf += 8;\n            size += 8;\n        }\n        break; case 'S': { // string, 32-bit fixed length prepended\n            char* s = va_arg(ap, char*);\n            int len = strlen(s);\n            pack32i(buf, len, le);\n            memcpy(buf + 4, s, len);\n            buf += 4 + len;\n            size += 4 + len;\n        }\n        break; case 's': { // string, 64-bit variable length prepended\n            char* s = va_arg(ap, char*);\n            int len = strlen(s);\n            int64_t L = pack64iv(buf, len);\n            memcpy(buf + L, s, len);\n            buf += L + len;\n            size += L + len;\n        }\n        break; case 'M': { // memblock, 32-bit fixed length prepended\n            int len = va_arg(ap, int);\n            char* s = va_arg(ap, char*);\n            pack32i(buf, len, le);\n            memcpy(buf + 4, s, len);\n            buf += 4 + len;\n            size += 4 + len;\n        }\n        break; case 'm': { // memblock, 64-bit variable length prepended\n            int len = va_arg(ap, int);\n            char* s = va_arg(ap, char*);\n            int64_t L = pack64iv(buf, len);\n            memcpy(buf + L, s, len);\n            buf += L + len;\n            size += L + len;\n        }\n        break; case 'z': { // memblock (zeroed)\n            int len = va_arg(ap, int);\n            memset(buf, 0, len);\n            buf += len;\n            size += len;\n        }\n        }\n    }\n\n    return (int)size;\n}\n\n\nint saveb(uint8_t *buf, const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n    int rc = saveb_( buf, fmt, ap);\n    va_end(ap);\n    return rc;\n}\nint loadb(const uint8_t *buf, const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n    int rc = loadb_( buf, fmt, ap);\n    va_end(ap);\n    return rc;\n}\n\nint savef(FILE *fp, const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n\n    // estimate bytes\n    int req = saveb_( 0, fmt, ap);\n\n    char stack[4096];\n    char *buf = req < 4096 ? stack : (char*)calloc(1, req + 1 );\n        int rc = saveb_(buf, fmt, ap);\n        fwrite(buf, req,1, fp);\n    if( !(req < 4096) ) free(buf);\n\n    va_end(ap);\n    return rc;\n}\nint loadf(FILE *fp, const char *fmt, ...) {\n    va_list ap;\n    va_start(ap, fmt);\n\n    // estimate bytes\n    int req = loadb_( 0, fmt, ap) * 2; // *2 in case it is underestimated\n\n    char stack[4096];\n    char *buf = req < 4096 ? stack : (char*)calloc(1, req + 1 );\n        fread(buf, req,1, fp);\n        int rc = loadb_(buf, fmt, ap);\n    if( !(req < 4096) ) free(buf);\n\n    va_end(ap);\n    return rc;\n}\n#endif\n\n#ifdef PACK_DEMO\ntypedef struct bootsector {\n    uint8_t jump_instruction[3];\n    uint8_t oem_name[8];\n    uint16_t bytes_per_sector;\n    uint8_t sectors_per_cluster;\n    uint16_t reserved_sectors;\n    uint8_t fat_copies;\n    uint16_t max_dirs;\n    uint16_t sector_count;\n    uint8_t media_descriptor;\n    uint16_t sectors_per_fat;\n    uint16_t sectors_per_head;\n    uint16_t heads;\n    uint32_t hidden_sectors;\n    uint32_t sector_countz;\n} bootsector;\nint main() {\n    const char *dna = \"3b8bhbhbbhhbhhhuu\"; // \"1c1h212122122233\"; \"i3c8chchchhchhhdd\"\n\n    bootsector fat = { {0,1,2},{3,4,5,6,7,8,9,10},11,12,13,14,15,16,17,18,19,20,21,22 };\n    hexdump(&fat, sizeof(bootsector));\n\n    FILE *fp = fopen(\"test.mbr\", \"wb\");\n    savef(fp, dna, &fat); // \n    fclose(fp);\n\n    memset(&fat, 0, sizeof(bootsector));\n\n    fp = fopen(\"test.mbr\", \"rb\");\n    loadf(fp, dna, &fat);\n    fclose(fp);\n\n    hexdump(&fat, sizeof(bootsector));\n}\n#endif\n"
  },
  {
    "path": "vault/buf_pack754.h",
    "content": "// float754.c packing ----------------------------------------------------------\n// [1] http://www.mrob.com/pub/math/floatformats.html#minifloat\n// [2] microfloat: [0.002 to 240] range.\n// [3] half float: can approximate any 16-bit unsigned integer or its reciprocal to 3 decimal places.\n// - rlyeh, public domain\n\n#pragma once\n#include <math.h>\n#include <stdint.h>\n\n#define pack754_8(f)    (  pack754((f),  8,  4)) //@r-lyeh, add microfloat [1][3]\n#define pack754_16(f)   (  pack754((f), 16,  5)) //@r-lyeh, add half [1][4]\n#define pack754_32(f)   (  pack754((f), 32,  8))\n#define pack754_64(f)   (  pack754((f), 64, 11))\n#define unpack754_8(u)  (unpack754((u),  8,  4)) //@r-lyeh, add microfloat\n#define unpack754_16(u) (unpack754((u), 16,  5)) //@r-lyeh, add half \n#define unpack754_32(u) (unpack754((u), 32,  8))\n#define unpack754_64(u) (unpack754((u), 64, 11))\n\n#if 1\n// [src] http://beej.us/guide/bgnet/output/html/multipage/advanced.html#serialization\n// Modified to encode NaN and Infinity as well.\n\n#pragma once\n#include <stdint.h>\n#include <math.h>\n\nstatic\nuint64_t pack754(long double f, unsigned bits, unsigned expbits)\n{\n    long double fnorm;\n    int shift;\n    long long sign, exp, significand;\n    unsigned significandbits = bits - expbits - 1; // -1 for sign bit\n\n    if (f == 0.0) return 0; // get this special case out of the way\n//@r{ beware! works for 32/64 only\n    else if (f ==  INFINITY) return 0x7f800000ULL << (bits - 32); // 0111 1111 1000\n    else if (f == -INFINITY) return 0xff800000ULL << (bits - 32);\n    else if (f != f)         return 0x7fc00000ULL << (bits - 32); // 0111 1111 1100 NaN\n//@r}\n\n    // check sign and begin normalization\n    if (f < 0) { sign = 1; fnorm = -f; }\n    else { sign = 0; fnorm = f; }\n\n    // get the normalized form of f and track the exponent\n    shift = 0;\n    while(fnorm >= 2.0) { fnorm /= 2.0; shift++; }\n    while(fnorm < 1.0) { fnorm *= 2.0; shift--; }\n    fnorm = fnorm - 1.0;\n\n    // calculate the binary form (non-float) of the significand data\n    significand = fnorm * ((1LL<<significandbits) + 0.5f);\n\n    // get the biased exponent\n    exp = shift + ((1<<(expbits-1)) - 1); // shift + bias\n\n    // return the final answer\n    return (sign<<(bits-1)) | (exp<<(bits-expbits-1)) | significand;\n}\n\nstatic\nlong double unpack754(uint64_t i, unsigned bits, unsigned expbits)\n{\n    long double result;\n    long long shift;\n    unsigned bias;\n    unsigned significandbits = bits - expbits - 1; // -1 for sign bit\n\n    if (i == 0) return 0.0;\n//@r{ beware! works for 32 only\n    else if (i == 0x7fc00000ULL) return  NAN;      //  NaN\n    else if (i == 0x7f800000ULL) return  INFINITY; // +Inf\n    else if (i == 0xff800000ULL) return -INFINITY; // -Inf\n//@r}\n\n    // pull the significand\n    result = (i&((1LL<<significandbits)-1)); // mask\n    result /= (1LL<<significandbits); // convert back to float\n    result += 1.0f; // add the one back on\n\n    // deal with the exponent\n    bias = (1<<(expbits-1)) - 1;\n    shift = ((i>>significandbits)&((1LL<<expbits)-1)) - bias;\n    while(shift > 0) { result *= 2.0; shift--; }\n    while(shift < 0) { result /= 2.0; shift++; }\n\n    // sign it\n    result *= (i>>(bits-1))&1? -1.0: 1.0;\n\n    return result;\n}\n#else\nstatic uint64_t pack754(long double f, unsigned bits, unsigned expbits) {\n    long double fnorm;\n    int shift;\n    long long sign, exp, significand;\n    unsigned significandbits = bits - expbits - 1; // -1 for sign bit\n\n//@r-lyeh{\n    #define FLOAT_NINF (((0xFFFFffffFFFFffffULL) >> significandbits) << significandbits)\n    #define FLOAT_PINF (((0x7FFFffffFFFFffffULL) >> significandbits) << significandbits)\n    #define FLOAT_NANF (FLOAT_PINF | (1ULL << (significandbits-1)))\n    #define FLOAT_NEG0 (1ULL << (bits-1))\n\n    /**/ if(f != f)     return FLOAT_NANF;\n    else if(f == 0.0f)  return signbit(f) ? FLOAT_NEG0 : 0;\n    else if(f/f != f/f) return f > 0 ? FLOAT_PINF : FLOAT_NINF;\n//@r-lyeh}\n\n    // check sign and begin normalization\n    if (f < 0) { sign = 1; fnorm = -f; }\n    else { sign = 0; fnorm = f; }\n\n    // get the normalized form of f and track the exponent\n    shift = 0;\n    while(fnorm >= 2.0) { fnorm /= 2.0; shift++; }\n    while(fnorm < 1.0) { fnorm *= 2.0; shift--; }\n    fnorm = fnorm - 1.0;\n\n    // calculate the binary form (non-float) of the significand data\n    significand = fnorm * ((1LL<<significandbits) + 0.5f);\n\n    // get the biased exponent\n    exp = shift + ((1<<(expbits-1)) - 1); // shift + bias\n\n    // return the final answer\n    return (sign<<(bits-1)) | (exp<<(bits-expbits-1)) | significand;\n}\n\nstatic long double unpack754(uint64_t i, unsigned bits, unsigned expbits) {\n    long double result;\n    long long shift;\n    unsigned bias;\n    unsigned significandbits = bits - expbits - 1; // -1 for sign bit\n\n//@r-lyeh{\n    /**/ if(i == 0)          return 0.0;\n    else if(i == FLOAT_NEG0) return -0.0;\n    else if(i == FLOAT_PINF) return INFINITY;\n    else if(i == FLOAT_NINF) return -INFINITY;\n    else if(i == FLOAT_NANF) return NAN;\n//@r-lyeh}\n\n    // pull the significand\n    result = (i&((1LL<<significandbits)-1)); // mask\n    result /= (1LL<<significandbits); // convert back to float\n    result += 1.0f; // add the one back on\n\n    // deal with the exponent\n    bias = (1<<(expbits-1)) - 1;\n    shift = ((i>>significandbits)&((1LL<<expbits)-1)) - bias;\n    while(shift > 0) { result *= 2.0; shift--; }\n    while(shift < 0) { result /= 2.0; shift++; }\n\n    // sign it\n    result *= (i>>(bits-1))&1? -1.0: 1.0;\n\n    return result;\n}\n#endif\n\ntypedef int static_assert_flt[ sizeof(float) == 4 ];\ntypedef int static_assert_dbl[ sizeof(double) == 8 ];\n\n"
  },
  {
    "path": "vault/buf_packhalf.h",
    "content": "// from ginger bill's gbmath.h (public domain)\n\n#ifndef HALF_H\n#define HALF_H\n\ntypedef uint16_t half;\nfloat half_to_float(half value);\nhalf float_to_half(float value);\n\n#endif\n\n#ifdef HALF_C\n#pragma once\n\nfloat half_to_float(half value) {\n    union { unsigned int i; float f; } result;\n    int s = (value >> 15) & 0x001;\n    int e = (value >> 10) & 0x01f;\n    int m =  value        & 0x3ff;\n\n    if (e == 0) {\n        if (m == 0) {\n            /* Plus or minus zero */\n            result.i = (unsigned int)(s << 31);\n            return result.f;\n        } else {\n            /* Denormalized number */\n            while (!(m & 0x00000400)) {\n                m <<= 1;\n                e -=  1;\n            }\n            e += 1;\n            m &= ~0x00000400;\n        }\n    } else if (e == 31) {\n        if (m == 0) {\n            /* Positive or negative infinity */\n            result.i = (unsigned int)((s << 31) | 0x7f800000);\n            return result.f;\n        } else {\n            /* Nan */\n            result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13));\n            return result.f;\n        }\n    }\n\n    e = e + (127 - 15);\n    m = m << 13;\n\n    result.i = (unsigned int)((s << 31) | (e << 23) | m);\n    return result.f;\n}\n\nhalf float_to_half(float value) {\n    union { unsigned int i; float f; } v;\n    int i, s, e, m;\n\n    v.f = value;\n    i = (int)v.i;\n\n    s =  (i >> 16) & 0x00008000;\n    e = ((i >> 23) & 0x000000ff) - (127 - 15);\n    m =   i        & 0x007fffff;\n\n    if (e <= 0) {\n        if (e < -10) return (half)s;\n        m = (m | 0x00800000) >> (1 - e);\n\n        if (m & 0x00001000)\n            m += 0x00002000;\n\n        return (half)(s | (m >> 13));\n    } else if (e == 0xff - (127 - 15)) {\n        if (m == 0) {\n            return (half)(s | 0x7c00); /* NOTE(bill): infinity */\n        } else {\n            /* NOTE(bill): NAN */\n            m >>= 13;\n            return (half)(s | 0x7c00 | m | (m == 0));\n        }\n    } else {\n        if (m & 0x00001000) {\n            m += 0x00002000;\n            if (m & 0x00800000) {\n                m = 0;\n                e += 1;\n            }\n        }\n        if (e > 30) {\n            float volatile f = 1e12f;\n            int j;\n            for (j = 0; j < 10; j++)\n                f *= f; /* NOTE(bill): Cause overflow */\n            return (half)(s | 0x7c00);\n        }\n        return (half)(s | (e << 10) | (m >> 13));\n    }\n}\n\n#endif\n"
  },
  {
    "path": "vault/buf_packint.h",
    "content": "// int packing -----------------------------------------------------------------\n// - rlyeh, public domain\n\n#pragma once\n#include <string.h>\n\n// pack16i() -- store a 16-bit int into a char buffer (like htons())\n// pack32i() -- store a 32-bit int into a char buffer (like htonl())\n// pack64i() -- store a 64-bit int into a char buffer (like htonl())\n\nstatic void pack16i(uint8_t *buf, uint16_t i, int swap) {\n    if( swap ) i = bswap16(i);\n    memcpy( buf, &i, sizeof(i) );\n}\n\nstatic void pack32i(uint8_t *buf, uint32_t i, int swap) {\n    if( swap ) i = bswap32(i);\n    memcpy( buf, &i, sizeof(i) );\n}\n\nstatic void pack64i(uint8_t *buf, uint64_t i, int swap) {\n    if( swap ) i = bswap64(i);\n    memcpy( buf, &i, sizeof(i) );\n}\n\n// unpack16i() -- unpack a 16-bit int from a char buffer (like ntohs())\n// unpack32i() -- unpack a 32-bit int from a char buffer (like ntohl())\n// unpack64i() -- unpack a 64-bit int from a char buffer (like ntohl())\n// changes unsigned numbers to signed if needed.\n\nstatic int16_t unpack16i(const uint8_t *buf, int swap) {\n    uint16_t i;\n    memcpy(&i, buf, sizeof(i));\n    if( swap ) i = bswap16(i);\n    return i <= 0x7fffu ? (int16_t)i : -1 -(uint16_t)(0xffffu - i);\n}\n\nstatic int32_t unpack32i(const uint8_t *buf, int swap) {\n    uint32_t i;\n    memcpy(&i, buf, sizeof(i));\n    if( swap ) i = bswap32(i);\n    return i <= 0x7fffffffu ? (int32_t)i : -1 -(int32_t)(0xffffffffu - i);\n}\n\nstatic int64_t unpack64i(const uint8_t *buf, int swap) {\n    uint64_t i;\n    memcpy(&i, buf, sizeof(i));\n    if( swap ) i = bswap64(i);\n    return i <= 0x7fffffffffffffffull ? (int64_t)i : -1 -(int64_t)(0xffffffffffffffffull - i);\n}\n\n"
  },
  {
    "path": "vault/buf_packvli.h",
    "content": "// vli varint spec (licensed under public domain, unlicense, CC0 and MIT-0: pick one).\n// - rlyeh.\n// 7 [0 xxxx xxx]                        7-bit value in  1 byte  (0-                127)\n// 7 [10 xxx xxx] [yyyyyyyy]            14-bit value in  2 bytes (0-             16,383)\n// 6 [110 xx xxx] [yyyyyyyy] [zzzzzzzz] 21-bit value in  3 bytes (0-          2,097,151)\n// 8 [111 00 xxx] [ 3 bytes]            27-bit value in  4 bytes (0-        134,217,727)\n// 8 [111 01 xxx] [ 4 bytes]            35-bit value in  5 bytes (0-     34,359,738,367)\n// 5 [111 10 xxx] [ 5 bytes]            43-bit value in  6 bytes (0-  8,796,093,022,207)\n// 8 [111 11 000] [ 6 bytes]            48-bit value in  7 bytes (0-281,474,976,710,655)\n// 8 [111 11 001] [ 7 bytes]            56-bit value in  8 bytes (...)\n// 8 [111 11 010] [ 8 bytes]            64-bit value in  9 bytes\n// 8 [111 11 011] [ 9 bytes]            72-bit value in 10 bytes\n// 8 [111 11 100] [10 bytes]            80-bit value in 11 bytes\n// A [111 11 101] [12 bytes]            96-bit value in 13 bytes\n// A [111 11 110] [14 bytes]           112-bit value in 15 bytes\n// A [111 11 111] [16 bytes]           128-bit value in 17 bytes\n// 1 1 2 3 = 7\n\n#pragma once\n\n#if 0 // try\n// 7 [0 xxxx xxx]                        7-bit value in   1 byte  (0-                  127)\n// 7 [10 xxx xxx] [yyyyyyyy]            14-bit value in   2 bytes (0-               16,383)\n// 6 [110 xx xxx] [yyyyyyyy] [zzzzzzzz] 21-bit value in   3 bytes (0-            2,097,151)\n// 8 [111 00 xxx] [ 3 bytes]            27-bit value in   4 bytes (0-          134,217,727)\n// 7 [111 01 xxx] [ 4 bytes]            35-bit value in   5 bytes (0-       34,359,738,367)\n// 8 [111 10 0xx] [ 5 bytes]            42-bit value in   6 bytes (0-    4,398,046,511,103)\n// 6 [111 10 1xx] [ 6 bytes]            50-bit value in   7 bytes (0-1,125,899,906,842,623)\n// 8 [111 11 000] [ 7 bytes]            56-bit value in   8 bytes (...)\n// 8 [111 11 001] [ 8 bytes]            64-bit value in   9 bytes\n// 8 [111 11 010] [ 9 bytes]            72-bit value in  10 bytes\n// 8 [111 11 011] [10 bytes]            80-bit value in  11 bytes\n// A [111 11 100] [12 bytes]            96-bit value in  13 bytes\n// A [111 11 101] [14 bytes]           112-bit value in  15 bytes\n// A [111 11 110] [16 bytes]           128-bit value in  17 bytes\n// N [111 11 111] [nn bytes]           custom bit value in N+1 bytes\n// 1 1 2 1 2 = 7\n#endif\n\n\n#include <stdio.h>\n#include <stdint.h>\n\nstatic uint64_t pack64uv( uint8_t *buffer, uint64_t value ) {\n    #define ADD(bits) *buffer++ = (value >>= bits)\n    if( value < (1ull<< 7) ) return *buffer = value, 1;\n    if( value < (1ull<<14) ) return *buffer++ = 0x80|(value&0x3f), ADD(6), 2;\n    if( value < (1ull<<21) ) return *buffer++ = 0xc0|(value&0x1f), ADD(5), ADD(8), 3;\n    if( value < (1ull<<27) ) return *buffer++ = 0xe0|(value&0x07), ADD(3), ADD(8), ADD(8), 4;\n    if( value < (1ull<<35) ) return *buffer++ = 0xe8|(value&0x07), ADD(3), ADD(8), ADD(8), ADD(8), 5;\n    if( value < (1ull<<43) ) return *buffer++ = 0xf0|(value&0x07), ADD(3), ADD(8), ADD(8), ADD(8), ADD(8), 6;\n    if( value < (1ull<<48) ) return *buffer++ = 0xf8|(value&0x00), ADD(0), ADD(8), ADD(8), ADD(8), ADD(8), ADD(8), 7;\n    if( value < (1ull<<56) ) return *buffer++ = 0xf9|(value&0x00), ADD(0), ADD(8), ADD(8), ADD(8), ADD(8), ADD(8), ADD(8), 8;\n  /*if( value < (1ull<<64))*/return *buffer++ = 0xfa|(value&0x00), ADD(0), ADD(8), ADD(8), ADD(8), ADD(8), ADD(8), ADD(8), ADD(8), 9;\n  /*...*/\n    #undef ADD\n}\nstatic uint64_t unpack64uv( const uint8_t *buffer, uint64_t *value ) {\n    uint64_t bytes, out = 0, shift = 0;\n    const int table[] = { 6,7,8,9,10,12,14,16 };\n    /**/ if( *buffer >= 0xf8 ) bytes = table[*buffer - 0xf8];\n    else if( *buffer >= 0xe0 ) bytes = 3 + ((*buffer>>3) & 3);\n    else if( *buffer >= 0xc0 ) bytes = 2;\n    else                       bytes = *buffer >= 0x80;\n\n    #define POP(bits) out = out | (uint64_t)*buffer++ << (shift += bits);\n    switch( bytes ) {\n        default:\n        break; case 0: out = *buffer++;\n        break; case 1: out = *buffer++ & 0x3f; POP(6);\n        break; case 2: out = *buffer++ & 0x1f; POP(5); POP(8);\n        break; case 3: out = *buffer++ & 0x07; POP(3); POP(8); POP(8);\n        break; case 4: out = *buffer++ & 0x07; POP(3); POP(8); POP(8); POP(8);\n        break; case 5: out = *buffer++ & 0x07; POP(3); POP(8); POP(8); POP(8); POP(8);\n        break; case 6: ++buffer; shift = -8;   POP(8); POP(8); POP(8); POP(8); POP(8); POP(8);\n        break; case 7: ++buffer; shift = -8;   POP(8); POP(8); POP(8); POP(8); POP(8); POP(8); POP(8);\n        break; case 8: ++buffer; shift = -8;   POP(8); POP(8); POP(8); POP(8); POP(8); POP(8); POP(8); POP(8);\n    }\n    #undef POP\n\n    return *value = out, bytes+1;\n}\n\nstatic uint64_t pack64iv( uint8_t *buffer, int64_t value_ ) {\n    uint64_t value = (uint64_t)((value_ >> 63) ^ (value_ << 1));\n    return pack64uv(buffer, value); /* convert sign|magnitude to magnitude|sign */\n}\n\nstatic uint64_t unpack64iv( const uint8_t *buffer, int64_t *value ) {\n    uint64_t out = 0, ret = unpack64uv( buffer, &out );\n    *value = ((out >> 1) ^ -(out & 1)); /* convert magnitude|sign to sign|magnitude */\n    return ret;\n}\n\n\n\n#if 0\n\n// variable int packing --------------------------------------------------------\n// vbyte, varint (signed)\n\nstatic uint64_t pack_LEB128( uint8_t *buffer, int64_t value_ ) {\n    /* convert sign|magnitude to magnitude|sign */\n    // uint64_t value = (uint64_t)value_; value = value & (1ull << 63) ? ~(value << 1) : (value << 1);\n    uint64_t value = (uint64_t)((value_ >> 63) ^ (value_ << 1)); // (branchless)\n    /* encode unsigned : 7-bit pack. MSB terminates stream */\n    const uint8_t *buffer0 = buffer;\n    while( value > 127 ) {\n        *buffer++ = value | 0x80; // (uint8_t)(( value & 0xFF ) | 0x80 );\n        value >>= 7;\n    }\n    *buffer++ = value;\n\n    return buffer - buffer0;\n}\nstatic uint64_t unpack_LEB128( const uint8_t *buffer, int64_t *value ) {\n    /* decode unsigned : 7-bit unpack. MSB terminates stream */\n    const uint8_t *buffer0 = buffer;\n    uint64_t out = 0, j = -7;\n    do {\n        out |= ( ((uint64_t)*buffer) & 0x7f) << (j += 7);\n    } while( (*buffer++) & 0x80 );\n    /* convert magnitude|sign to sign|magnitude */\n    // *value = out & (1) ? ~(out >> 1) : (out >> 1);\n    *value = ((out >> 1) ^ -(out & 1)); // (branchless)\n    return buffer - buffer0;\n}\n\n#endif\n\n\n#ifdef VLI_DEMO\n\nint main() {\n    int tests = 0, passes = 0;\n\n    #define testi(v) do { \\\n        int64_t val = v; \\\n        char out[16]; \\\n        int len = pack64iv(out, val); \\\n        int64_t in = ~val; \\\n        unpack64iv(out, &in); \\\n        int ok = val == in; ++tests; passes += ok; \\\n        printf(\"%c %02d/%02d (-) %#llx (%llu) <-> %d bytes <-> %#llx (%llu)\\n\", \"NY\"[ok], passes, tests, val, val, len, in, in); \\\n    } while(0)\n\n    #define testu(v) do { \\\n        uint64_t val = (v); \\\n        char out[16]; \\\n        int len = pack64uv(out, val); \\\n        uint64_t in = ~val; \\\n        unpack64uv(out, &in); \\\n        int ok = val == in; ++tests; passes += ok; \\\n        printf(\"%c %02d/%02d (+) %#llx (%llu) <-> %d bytes <-> %#llx (%llu)\\n\", \"NY\"[ok], passes, tests, val, val, len, in, in); \\\n    } while(0)\n\n    #define test(v) do { testi(v); testu(v); } while(0)\n\n    test(0);\n    test((1ull<<7)-1);\n    test( 1ull<<7);\n    test((1ull<<14)-1);\n    test( 1ull<<14);\n    test((1ull<<21)-1);\n    test( 1ull<<21);\n    test((1ull<<27)-1);\n    test( 1ull<<27);\n    test((1ull<<35)-1);\n    test( 1ull<<35);\n    test((1ull<<48)-1);\n    test( 1ull<<48);\n    test(~0ull-1);\n    test(~0ull);\n\n    printf(\"%d tests, %d errors\\n\", tests, tests - passes);\n}\n\n#endif\n"
  },
  {
    "path": "vault/buf_zigzag.c",
    "content": "// zigzag de/encoder\n// - rlyeh, public domain\n\n#ifndef ZIGZAG_H\n#define ZIGZAG_H\n#include <stdint.h>\n\nuint64_t zig64( int64_t value ); // convert sign|magnitude to magnitude|sign\nint64_t zag64( uint64_t value ); // convert magnitude|sign to sign|magnitude\n\n#endif\n\n// -----------------------------------------------------------------------------\n\n#ifdef ZIGZAG_C\n#pragma once\n\nuint64_t zig64( int64_t value ) { // convert sign|magnitude to magnitude|sign\n    return (value >> 63) ^ (value << 1);\n}\nint64_t zag64( uint64_t value ) { // convert magnitude|sign to sign|magnitude\n    return (value >> 1) ^ -(value & 1); \n}\n\n#ifdef ZIGZAG_DEMO\n#include <stdio.h>\nint main() {\n    int16_t x = -1000;\n    printf(\"%d -> %llu %llx -> %lld\\n\", x, zig64(x), zig64(x), zag64(zig64(x)));\n}\n#define main main__\n#endif // ZIGZAG_DEMO\n#endif // ZIGZAG_C\n"
  },
  {
    "path": "vault/c.c",
    "content": "// - rlyeh, public domain\n\n#ifdef C_C\n#pragma once\n#define BENCHMARK_C\n#define IFDEF_C\n#define OVERLOAD_C\n#define WITH_C\n#endif\n\n#include \"c_benchmark.c\"\n#include \"c_ifdef.c\"\n#include \"c_overload.c\"\n#include \"c_with.c\"\n#include \"c_incbin.h\"\n\n#include \"c_section.c\"\n#include \"c_alignas.c\"\n#include \"c_thread.c\"\n#include \"c_plan.c\"\n\n#include \"c_once.c\"\n#include \"c_checkva.c\"\n#include \"c_cc4.c\" // after c_ifdef\n"
  },
  {
    "path": "vault/c_alignas.c",
    "content": "// - rlyeh, public domain\n\n#pragma once\n\n#if __STDC_VERSION__ >= 201112L\n#   ifndef _MSC_VER\n#   include <stdalign.h>\n#   endif\n#   define ALIGNAS(bytes) alignas(bytes)\n#else\n#   define ALIGNAS(bytes)\n#endif\n"
  },
  {
    "path": "vault/c_benchmark.c",
    "content": "// - rlyeh, public domain\n\n#ifndef BENCHMARK_H\n#define BENCHMARK_H\n\n#include <stdio.h>\n#ifdef _MSC_VER\n#include <omp.h>\n#define benchmark(t,...) \\\n    for(double b_=omp_get_wtime(), e_=b_; e_==b_; t=(((e_=omp_get_wtime())-b_)*1.0), \\\n        (void)(!0[\"\" #__VA_ARGS__] ? 0 : (printf(\"\" __VA_ARGS__), printf(\" (%.4fs)\\n\",t))))\n#else\n#include <time.h>\n#define benchmark(t,...) \\\n    for(clock_t b_=clock(), e_=b_; e_==b_; t=(((e_=clock())-b_)*1.0/CLOCKS_PER_SEC), \\\n        (void)(!0[\"\" #__VA_ARGS__] ? 0 : (printf(\"\" __VA_ARGS__), printf(\" (%.3fs)\\n\",t))))\n#endif\n\n#endif // BENCHMARK_H\n\n#ifdef BENCHMARK_DEMO\n#pragma once\nint main() {\n    double t;\n    benchmark(t, \"benchmark i/o, %d times\", 1000) {\n        for(int i = 0; i < 1000; ++i) {\n            fclose(fopen(__FILE__,\"rb\"));\n        }\n    }\n    benchmark(t) { // benchmark title (as seen above) is optional\n        for(int i = 0; i < 1000; ++i) {\n            fclose(fopen(__FILE__,\"rb\"));\n        }\n    }\n}\n#define main __main\n#endif // BENCHMARK_DEMO\n"
  },
  {
    "path": "vault/c_cc4.c",
    "content": "#pragma once\n\n#define CC4(abcd)  ((0[#abcd \"\\0\\0\\0\\0\"] << 24) | (1[#abcd \"\\0\\0\\0\\0\"] << 16) | (2[#abcd \"\\0\\0\\0\\0\"] << 8) | (3[#abcd \"\\0\\0\\0\\0\"] << 0))\n#if LITTLE\n#define CC4_FMT(i) ((i)>>24)&255,((i)>>16)&255,((i)>> 8)&255,((i)>> 0)&255\n#else\n#define CC4_FMT(i) ((i)>> 0)&255,((i)>> 8)&255,((i)>>16)&255,((i)>>24)&255\n#endif\n\n/*\nint main() {\n    int x = CC4(user);\n    printf(\"%#x %c%c%c%c\\n\", x, CC4_FMT(x));\n}\n*/\n"
  },
  {
    "path": "vault/c_checkva.c",
    "content": "#pragma once\n\n// MSVC2015 trick by doynax (check+dead code elimination)\n// see: https://stackoverflow.com/a/42313782\n#define CHECK_VA(...) \\\n(printf || printf(__VA_ARGS__), (__VA_ARGS__))\n\n// usage:\n// #define my_printf(...) my_printf(CHECK_VA(__VA_ARGS__))\n"
  },
  {
    "path": "vault/c_countof.c",
    "content": "// - rlyeh, public domain\n\n#pragma once\n\n#ifndef COUNTOF\n#define COUNTOF(x) (int)(sizeof(x)/sizeof(0[x]))\n#endif\n"
  },
  {
    "path": "vault/c_ifdef.c",
    "content": "// - rlyeh, public domain\n\n#ifndef IFDEF_H\n#define IFDEF_H\n\n#define IF(x,T,...)           IF_(x)(T,__VA_ARGS__/*F*/)\n#define IFN(x,T,...)          IF_(x)(__VA_ARGS__/*F*/,T)\n#define IF_(x)                IF_DETECT(x)\n#define IF_DETECT(...)        IF_DETECT_##__VA_ARGS__\n#define IF_DETECT_0(t,...)    __VA_ARGS__\n#define IF_DETECT_1(t,...)    t\n\n#define IFDEF IF\n#define IFNDEF IFN\n\n// -----------------------------------------------------------------------------\n\n// build type\n#define DEBUG          0\n#define DEBUGOPT       0\n#define RELEASE        0\n\n// endianness symbols\n#define BIG            0\n#define LITTLE         0\n\n// arch wordsize and cacheline symbols\n#define X32            0\n#define X64            0\n#define L64            0\n#define L128           0\n\n// architecture symbols\n#define ARM            0\n#define PPC            0\n#define INTEL          0\n#define JIT            0\n\n// language symbols\n#define C89            0\n#define C99            0\n#define C11            0\n#define CPP            0\n#define CPP03          0\n#define CPP11          0\n#define EXCEPTIONS     0\n\n// language features\n#define COMPUTED_GOTO  0\n#define FLEXIBLE_ARRAY 0\n\n// compiler symbols\n#define CLANG          0\n#define GCC            0\n#define ICC            0\n#define MINGW          0\n#define MSC            0\n#define SNC            0\n#define GCC_COMPAT     0\n\n// platform symbols\n#define ANDROID        0\n#define BSD            0\n#define HTML5          0\n#define IOS            0\n#define LINUX          0\n#define OSX            0\n#define PS4            0\n#define RASPBERRYPI    0\n#define STEAMLINK      0\n#define UNIX           0\n#define WINDOWS        0\n#define XBOX1          0\n\n// detect build type (@todo: check _DEBUG compatibility in non-msvc compilers)\n// we assume that we are on shipping build if asserts are removed (ie, NDEBUG is defined)\n#if defined NDEBUG && defined _DEBUG\n#   undef  DEBUGOPT\n#   define DEBUGOPT    1\n#elif defined NDEBUG\n#   undef  RELEASE\n#   define RELEASE     1\n#else\n#   undef  DEBUG\n#   define DEBUG       1\n#endif\n\n// detect compiler\n// also compiler arm __CC_ARM, ibm __xlc__ || __xlC__, sun __SUNPRO_C || __SUNPRO_CC\n#if   defined __ICC // __ICL, __INTEL_COMPILER\n#   undef  ICC\n#   define ICC         1\n#elif defined __SNC__\n#   undef  SNC\n#   define SNC         1\n#elif defined __clang__ // before gcc\n#   undef  CLANG\n#   define CLANG       1\n#elif defined __GNUC__\n#   undef  GCC\n#   define GCC         1\n#elif defined _MSC_VER\n#   undef  MSC\n#   define MSC         1\n#elif defined __MINGW32__\n#   undef  MINGW\n#   define MINGW       1\n#endif\n\n// detect compilers in gcc compatibility mode (clang, icc, snc)\n#if defined __GNUC__ && !defined (__GNUC_PATCHLEVEL__)\n#   undef  GCC\n#   define GCC         1\n#endif\n\n// detect C++ language and version\n#ifdef __cplusplus\n#   undef  CPP\n#   define CPP         1\n#   if (__cplusplus < 201103L && !defined _MSC_VER) || (defined _MSC_VER && _MSC_VER < 1700)\n#   undef  CPP03\n#   define CPP03       1\n#   else\n#   undef  CPP11\n#   define CPP11       1\n#   endif\n#else // detect C language and version\n#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L\n#   undef  C11\n#   define C11         1\n#elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L\n#   undef  C99\n#   define C99         1\n#else\n#   undef  C89\n#   define C89         1\n#endif\n#endif\n\n// detect language features\n#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L // C99\n#   undef  FLEXIBLE_ARRAY\n#   define FLEXIBLE_ARRAY // char data[FLEXIBLE_ARRAY]; -> char data[];\n#endif\n\n#ifdef __GNUC__\n#   undef  COMPUTED_GOTO\n#   define COMPUTED_GOTO 1\n#endif\n\n// detect c++ exceptions\n#if defined __cplusplus && ( \\\n    (defined _HAS_EXCEPTIONS && _HAS_EXCEPTIONS) || \\\n    (defined _STLP_USE_EXCEPTIONS && _STLP_USE_EXCEPTIONS) || \\\n    (defined HAVE_EXCEPTIONS) || \\\n    (defined __EXCEPTIONS) || \\\n    (defined _CPPUNWIND) )\n#   undef  EXCEPTIONS\n#   define EXCEPTIONS  1\n#endif\n\n#ifdef __has_feature\n#if __has_feature(cxx_exceptions)\n#   undef  EXCEPTIONS\n#   define EXCEPTIONS  1\n#endif\n#endif\n\n// detect endianness\n// also BE if (*(uint16_t *)\"\\0\\xff\" < 0x100)\n#if defined __BIG_ENDIAN__ || defined __ARMEB__ || defined __THUMBEB__ || defined __MIPSEB__ || (defined __BYTE_ORDER__ && __BYTE_ORDER__==__BIG_ENDIAN)\n#   undef  BIG\n#   define BIG         1\n#else\n#   undef  LITTLE\n#   define LITTLE      1\n#endif\n\n\n// detect architecture\n// also __mips__ __mips (L64), __ia64, __sparc, __alpha, __hppa, __avr32__, __sh__, __itanium__|_M_IA64\n#if   defined _M_ARM // __aarch64__ __arm__\n#   undef  ARM\n#   define ARM         1\n#elif defined _M_PPC // __ppc64__ __ppc__ __powerpc__ __powerpc64__ __powerpc\n#   undef  PPC\n#   define PPC         1\n#elif defined _M_IX86 || defined _M_X64\n#   undef  INTEL\n#   define INTEL       1\n#else // likely VM/JIT\n#   undef  JIT\n#   define JIT         1\n#endif\n\n// detect wordsize\n#include <stdint.h>\n#  if defined INTPTR_MAX && INTPTR_MAX == INT32_MAX\n#   undef  X32\n#   define X32      1\n#elif defined INTPTR_MAX && INTPTR_MAX == INT64_MAX // __x86_64__ _M_X64 __aarch64__ __powerpc64__ __ppc64__ __itanium__ _M_IA64\n#   undef  X64\n#   define X64      1\n#endif\n\n// detect cache line size\n#if PPC\n#   undef  L128\n#   define L128    1\n#else\n#   undef  L64\n#   define L64     1\n#endif\n\n// detect platform\n// also CYG __CYGWIN__, QNX __QNXNTO__, SOL __sun, __hpux, _AIX, __WINDOWS__ (watcom), _WINDOWS\n#  if defined __EMSCRIPTEN__\n#   undef  HTML5\n#   define HTML5       1\n#elif defined _XBOX_ONE || defined _DURANGO\n#   undef  XBOX1\n#   define XBOX1       1 // before windows\n#elif defined _WIN32 || defined __MINGW32__\n#   undef  WINDOWS\n#   define WINDOWS     1\n#elif defined __ANDROID__\n#   undef  ANDROID\n#   define ANDROID     1 // before linux\n#elif defined __ORBIS__\n#   undef  PS4\n#   define PS4         1 // before linux\n#elif defined __STEAMLINK__\n#   undef  STEAMLINK\n#   define STEAMLINK   1 // before linux\n#elif defined __VCCOREVER__\n#   undef  RASPBERRYPI\n#   define RASPBERRYPI 1 // before linux\n#elif defined __linux__\n#   undef  LINUX\n#   define LINUX       1 // before unix\n#elif defined __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ || defined __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ // TARGET_OS_IPHONE == 1 \n#   undef  IOS\n#   define IOS         1 // before bsd\n#elif defined __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ || defined __APPLE__ // TARGET_OS_MAC == 1\n#   undef  OSX\n#   define OSX         1 // before bsd\n#elif defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __DragonFly__\n#   undef  BSD\n#   define BSD         1 // before unix\n#elif defined __unix__\n#   undef  UNIX\n#   define UNIX        1\n#endif\n\n#ifdef IFDEF_DEMO\n#pragma once\n#include <stdio.h>\nint main() {\n    // compile-time if\n    int debug = 0; IF(DEBUG, debug = 1);\n    // compile-time if-else\n    const char *arch = IF(X64, \"64\", \"32\") \"-bit arch\";\n    // compile-time if-else-if\n    const char *cpu = \"CPU-\" IF(INTEL, \"Intel\", IF(ARM, \"ARM\", \"Unknown\"));\n\n    // symbols are boolean preprocessor directives as well\n    #if DEBUG\n    debug = 1;\n    #endif\n\n    // debug all symbols\n    puts( 1 + \n        IF(X32, \"+X32\") IF(X64, \"+X64\")\n        IF(L64, \"+L64\") IF(L128, \"+L128\")\n\n        IF(BIG, \"+BIG\") IF(LITTLE, \"+LITTLE\")\n        IF(ARM, \"+ARM\") IF(PPC, \"+PPC\") IF(INTEL, \"+INTEL\") IF(JIT, \"+JIT\")\n\n        IF(DEBUG, \"+DEBUG\") IF(DEBUGOPT, \"+DEBUGOPT\") IF(RELEASE, \"+RELEASE\")\n\n        IF(C89, \"+C89\") IF(C99, \"+C99\") IF(C11, \"+C11\")\n        IF(CPP, \"+CPP\") IF(CPP03, \"+CPP03\") IF(CPP11, \"+CPP11\") IF(EXCEPTIONS, \"+EXCEPT\")\n\n        IF(MSC, \"+MSC\") IF(SNC, \"+SNC\") IF(ICC, \"+ICC\") IF(GCC, \"+GCC\")\n        IF(CLANG, \"+CLANG\") IF(MINGW, \"+MINGW\") IF(GCC_COMPAT, \"+GCC_COMPAT\")\n        \n        IF(HTML5, \"+HTML5\") \n        IF(BSD, \"+BSD\") IF(UNIX, \"+UNIX\")\n        IF(IOS, \"+IOS\") IF(ANDROID, \"+ANDROID\")\n        IF(XBOX1, \"+XBOX1\") IF(PS4, \"+PS4\")\n        IF(WINDOWS, \"+WINDOWS\") IF(LINUX, \"+LINUX\") IF(OSX, \"+OSX\")\n        IF(RASPBERRYPI, \"+RASPBERRYPI\") IF(STEAMLINK, \"+STEAMLINK\")\n    );\n}\n#define main __main\n#endif // IFDEF_DEMO\n#endif // IFDEF_H\n"
  },
  {
    "path": "vault/c_incbin.h",
    "content": "/**\n * @file c_incbin.h\n * @author Dale Weiler\n * @brief Utility for including binary files\n *\n * Facilities for including binary files into the current translation unit and\n * making use from them externally in other translation units.\n *\n * ---\n *\n * This is free and unencumbered software released into the public domain.\n * \n * Anyone is free to copy, modify, publish, use, compile, sell, or\n * distribute this software, either in source code form or as a compiled\n * binary, for any purpose, commercial or non-commercial, and by any\n * means.\n * \n * In jurisdictions that recognize copyright laws, the author or authors\n * of this software dedicate any and all copyright interest in the\n * software to the public domain. We make this dedication for the benefit\n * of the public at large and to the detriment of our heirs and\n * successors. We intend this dedication to be an overt act of\n * relinquishment in perpetuity of all present and future rights to this\n * software under copyright law.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n * \n * For more information, please refer to <http://unlicense.org/>\n */\n\n#if 1\n#elif 0\n// Usage:\n#include <assert.h>\n#include <stdlib.h>\n#include \"c_incbin.h\"\n\nINCBIN(Lorem, \"loremipsum.txt\");\nINCBIN(Onebyte, \"onebyte.txt\");\nINCBIN(Sevenbytes, \"sevenbytes.txt\");\n\nint main(int argc, char **argv) {\n    assert(gLoremSize==962);\n    assert(&gLoremData[gLoremSize] == (const unsigned char*) &gLoremEnd);\n\n    assert(gOnebyteSize == 1);\n    assert(&gOnebyteData[gOnebyteSize] == (const unsigned char*) &gOnebyteEnd);\n\n    assert(gSevenbytesSize==7);\n    assert(&gSevenbytesData[gSevenbytesSize] == (const unsigned char*) &gSevenbytesEnd);\n    exit(0);\n}\n#endif\n\n#ifndef INCBIN_H\n#define INCBIN_H\n#include <limits.h>\n#if   defined(__AVX512BW__) || \\\n      defined(__AVX512CD__) || \\\n      defined(__AVX512DQ__) || \\\n      defined(__AVX512ER__) || \\\n      defined(__AVX512PF__) || \\\n      defined(__AVX512VL__) || \\\n      defined(__AVX512F__)\n# define INCBIN_ALIGNMENT_INDEX 6\n#elif defined(__AVX__)      || \\\n      defined(__AVX2__)\n# define INCBIN_ALIGNMENT_INDEX 5\n#elif defined(__SSE__)      || \\\n      defined(__SSE2__)     || \\\n      defined(__SSE3__)     || \\\n      defined(__SSSE3__)    || \\\n      defined(__SSE4_1__)   || \\\n      defined(__SSE4_2__)   || \\\n      defined(__neon__)\n# define INCBIN_ALIGNMENT_INDEX 4\n#elif ULONG_MAX != 0xffffffffu\n# define INCBIN_ALIGNMENT_INDEX 3\n# else\n# define INCBIN_ALIGNMENT_INDEX 2\n#endif\n\n/* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */\n#define INCBIN_ALIGN_SHIFT_0 1\n#define INCBIN_ALIGN_SHIFT_1 2\n#define INCBIN_ALIGN_SHIFT_2 4\n#define INCBIN_ALIGN_SHIFT_3 8\n#define INCBIN_ALIGN_SHIFT_4 16\n#define INCBIN_ALIGN_SHIFT_5 32\n#define INCBIN_ALIGN_SHIFT_6 64\n\n/* Actual alignment value */\n#define INCBIN_ALIGNMENT \\\n    INCBIN_CONCATENATE( \\\n        INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \\\n        INCBIN_ALIGNMENT_INDEX)\n\n/* Stringize */\n#define INCBIN_STR(X) \\\n    #X\n#define INCBIN_STRINGIZE(X) \\\n    INCBIN_STR(X)\n/* Concatenate */\n#define INCBIN_CAT(X, Y) \\\n    X ## Y\n#define INCBIN_CONCATENATE(X, Y) \\\n    INCBIN_CAT(X, Y)\n/* Deferred macro expansion */\n#define INCBIN_EVAL(X) \\\n    X\n#define INCBIN_INVOKE(N, ...) \\\n    INCBIN_EVAL(N(__VA_ARGS__))\n\n/* Green Hills uses a different directive for including binary data */\n#if defined(__ghs__)\n#  if (__ghs_asm == 2)\n#    define INCBIN_MACRO \".file\"\n/* Or consider the \".myrawdata\" entry in the ld file */\n#  else\n#    define INCBIN_MACRO \"\\tINCBIN\"\n#  endif\n#else\n#  define INCBIN_MACRO \".incbin\"\n#endif\n\n#ifndef _MSC_VER\n#  define INCBIN_ALIGN \\\n    __attribute__((aligned(INCBIN_ALIGNMENT)))\n#else\n#  define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT))\n#endif\n\n#if defined(__arm__) || /* GNU C and RealView */ \\\n    defined(__arm) || /* Diab */ \\\n    defined(_ARM) /* ImageCraft */\n#  define INCBIN_ARM\n#endif\n\n#ifdef __GNUC__\n/* Utilize .balign where supported */\n#  define INCBIN_ALIGN_HOST \".balign \" INCBIN_STRINGIZE(INCBIN_ALIGNMENT) \"\\n\"\n#  define INCBIN_ALIGN_BYTE \".balign 1\\n\"\n#elif defined(INCBIN_ARM)\n/*\n * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is\n * the shift count. This is the value passed to `.align'\n */\n#  define INCBIN_ALIGN_HOST \".align \" INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) \"\\n\"\n#  define INCBIN_ALIGN_BYTE \".align 0\\n\"\n#else\n/* We assume other inline assembler's treat `.align' as `.balign' */\n#  define INCBIN_ALIGN_HOST \".align \" INCBIN_STRINGIZE(INCBIN_ALIGNMENT) \"\\n\"\n#  define INCBIN_ALIGN_BYTE \".align 1\\n\"\n#endif\n\n/* INCBIN_CONST is used by incbin.c generated files */\n#if defined(__cplusplus)\n#  define INCBIN_EXTERNAL extern \"C\"\n#  define INCBIN_CONST    extern const\n#else\n#  define INCBIN_EXTERNAL extern\n#  define INCBIN_CONST    const\n#endif\n\n/**\n * @brief Optionally override the linker section into which data is emitted.\n *\n * @warning If you use this facility, you'll have to deal with platform-specific linker output\n * section naming on your own\n *\n * Overriding the default linker output section, e.g for esp8266/Arduino:\n * @code\n * #define INCBIN_OUTPUT_SECTION \".irom.text\"\n * #include \"incbin.h\"\n * INCBIN(Foo, \"foo.txt\");\n * // Data is emitted into program memory that never gets copied to RAM\n * @endcode\n */\n#if !defined(INCBIN_OUTPUT_SECTION)\n#  if defined(__APPLE__)\n#    define INCBIN_OUTPUT_SECTION         \".const_data\"\n#  else\n#    define INCBIN_OUTPUT_SECTION         \".rodata\"\n#  endif\n#endif\n\n#if defined(__APPLE__)\n/* The directives are different for Apple branded compilers */\n#  define INCBIN_SECTION         INCBIN_OUTPUT_SECTION \"\\n\"\n#  define INCBIN_GLOBAL(NAME)    \".globl \" INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME \"\\n\"\n#  define INCBIN_INT             \".long \"\n#  define INCBIN_MANGLE          \"_\"\n#  define INCBIN_BYTE            \".byte \"\n#  define INCBIN_TYPE(...)\n#else\n#  define INCBIN_SECTION         \".section \" INCBIN_OUTPUT_SECTION \"\\n\"\n#  define INCBIN_GLOBAL(NAME)    \".global \" INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME \"\\n\"\n#  if defined(__ghs__)\n#    define INCBIN_INT           \".word \"\n#  else\n#    define INCBIN_INT           \".int \"\n#  endif\n#  if defined(__USER_LABEL_PREFIX__)\n#    define INCBIN_MANGLE        INCBIN_STRINGIZE(__USER_LABEL_PREFIX__)\n#  else\n#    define INCBIN_MANGLE        \"\"\n#  endif\n#  if defined(INCBIN_ARM)\n/* On arm assemblers, `@' is used as a line comment token */\n#    define INCBIN_TYPE(NAME)    \".type \" INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME \", %object\\n\"\n#  elif defined(__MINGW32__) || defined(__MINGW64__)\n/* Mingw doesn't support this directive either */\n#    define INCBIN_TYPE(NAME)\n#  else\n/* It's safe to use `@' on other architectures */\n#    define INCBIN_TYPE(NAME)    \".type \" INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME \", @object\\n\"\n#  endif\n#  define INCBIN_BYTE            \".byte \"\n#endif\n\n/* List of style types used for symbol names */\n#define INCBIN_STYLE_CAMEL 0\n#define INCBIN_STYLE_SNAKE 1\n\n/**\n * @brief Specify the prefix to use for symbol names.\n *\n * By default this is `g', producing symbols of the form:\n * @code\n * #include \"incbin.h\"\n * INCBIN(Foo, \"foo.txt\");\n *\n * // Now you have the following symbols:\n * // const unsigned char gFooData[];\n * // const unsigned char *const gFooEnd;\n * // const unsigned int gFooSize;\n * @endcode\n *\n * If however you specify a prefix before including: e.g:\n * @code\n * #define INCBIN_PREFIX incbin\n * #include \"incbin.h\"\n * INCBIN(Foo, \"foo.txt\");\n *\n * // Now you have the following symbols instead:\n * // const unsigned char incbinFooData[];\n * // const unsigned char *const incbinFooEnd;\n * // const unsigned int incbinFooSize;\n * @endcode\n */\n#if !defined(INCBIN_PREFIX)\n#  define INCBIN_PREFIX g\n#endif\n\n/**\n * @brief Specify the style used for symbol names.\n *\n * Possible options are\n * - INCBIN_STYLE_CAMEL \"CamelCase\"\n * - INCBIN_STYLE_SNAKE \"snake_case\"\n *\n * Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form:\n * @code\n * #include \"incbin.h\"\n * INCBIN(Foo, \"foo.txt\");\n *\n * // Now you have the following symbols:\n * // const unsigned char <prefix>FooData[];\n * // const unsigned char *const <prefix>FooEnd;\n * // const unsigned int <prefix>FooSize;\n * @endcode\n *\n * If however you specify a style before including: e.g:\n * @code\n * #define INCBIN_STYLE INCBIN_STYLE_SNAKE\n * #include \"incbin.h\"\n * INCBIN(foo, \"foo.txt\");\n *\n * // Now you have the following symbols:\n * // const unsigned char <prefix>foo_data[];\n * // const unsigned char *const <prefix>foo_end;\n * // const unsigned int <prefix>foo_size;\n * @endcode\n */\n#if !defined(INCBIN_STYLE)\n#  define INCBIN_STYLE INCBIN_STYLE_CAMEL\n#endif\n\n/* Style lookup tables */\n#define INCBIN_STYLE_0_DATA Data\n#define INCBIN_STYLE_0_END End\n#define INCBIN_STYLE_0_SIZE Size\n#define INCBIN_STYLE_1_DATA _data\n#define INCBIN_STYLE_1_END _end\n#define INCBIN_STYLE_1_SIZE _size\n\n/* Style lookup: returning identifier */\n#define INCBIN_STYLE_IDENT(TYPE) \\\n    INCBIN_CONCATENATE( \\\n        INCBIN_STYLE_, \\\n        INCBIN_CONCATENATE( \\\n            INCBIN_EVAL(INCBIN_STYLE), \\\n            INCBIN_CONCATENATE(_, TYPE)))\n\n/* Style lookup: returning string literal */\n#define INCBIN_STYLE_STRING(TYPE) \\\n    INCBIN_STRINGIZE( \\\n        INCBIN_STYLE_IDENT(TYPE)) \\\n\n/* Generate the global labels by indirectly invoking the macro with our style\n * type and concatenating the name against them. */\n#define INCBIN_GLOBAL_LABELS(NAME, TYPE) \\\n    INCBIN_INVOKE( \\\n        INCBIN_GLOBAL, \\\n        INCBIN_CONCATENATE( \\\n            NAME, \\\n            INCBIN_INVOKE( \\\n                INCBIN_STYLE_IDENT, \\\n                TYPE))) \\\n    INCBIN_INVOKE( \\\n        INCBIN_TYPE, \\\n        INCBIN_CONCATENATE( \\\n            NAME, \\\n            INCBIN_INVOKE( \\\n                INCBIN_STYLE_IDENT, \\\n                TYPE)))\n\n/**\n * @brief Externally reference binary data included in another translation unit.\n *\n * Produces three external symbols that reference the binary data included in\n * another translation unit.\n *\n * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with\n * \"Data\", as well as \"End\" and \"Size\" after. An example is provided below.\n *\n * @param NAME The name given for the binary data\n *\n * @code\n * INCBIN_EXTERN(Foo);\n *\n * // Now you have the following symbols:\n * // extern const unsigned char <prefix>FooData[];\n * // extern const unsigned char *const <prefix>FooEnd;\n * // extern const unsigned int <prefix>FooSize;\n * @endcode\n */\n#define INCBIN_EXTERN(NAME) \\\n    INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \\\n        INCBIN_CONCATENATE( \\\n            INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \\\n            INCBIN_STYLE_IDENT(DATA))[]; \\\n    INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \\\n    INCBIN_CONCATENATE( \\\n        INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \\\n        INCBIN_STYLE_IDENT(END)); \\\n    INCBIN_EXTERNAL const unsigned int \\\n        INCBIN_CONCATENATE( \\\n            INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \\\n            INCBIN_STYLE_IDENT(SIZE))\n\n/**\n * @brief Include a binary file into the current translation unit.\n *\n * Includes a binary file into the current translation unit, producing three symbols\n * for objects that encode the data and size respectively.\n *\n * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with\n * \"Data\", as well as \"End\" and \"Size\" after. An example is provided below.\n *\n * @param NAME The name to associate with this binary data (as an identifier.)\n * @param FILENAME The file to include (as a string literal.)\n *\n * @code\n * INCBIN(Icon, \"icon.png\");\n *\n * // Now you have the following symbols:\n * // const unsigned char <prefix>IconData[];\n * // const unsigned char *const <prefix>IconEnd;\n * // const unsigned int <prefix>IconSize;\n * @endcode\n *\n * @warning This must be used in global scope\n * @warning The identifiers may be different if INCBIN_STYLE is not default\n *\n * To externally reference the data included by this in another translation unit\n * please @see INCBIN_EXTERN.\n */\n#ifdef _MSC_VER\n#define INCBIN(NAME, FILENAME) \\\n    INCBIN_EXTERN(NAME)\n#else\n#define INCBIN(NAME, FILENAME) \\\n    __asm__(INCBIN_SECTION \\\n            INCBIN_GLOBAL_LABELS(NAME, DATA) \\\n            INCBIN_ALIGN_HOST \\\n            INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) \":\\n\" \\\n            INCBIN_MACRO \" \\\"\" FILENAME \"\\\"\\n\" \\\n            INCBIN_GLOBAL_LABELS(NAME, END) \\\n            INCBIN_ALIGN_BYTE \\\n            INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) \":\\n\" \\\n                INCBIN_BYTE \"1\\n\" \\\n            INCBIN_GLOBAL_LABELS(NAME, SIZE) \\\n            INCBIN_ALIGN_HOST \\\n            INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) \":\\n\" \\\n                INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) \" - \" \\\n                           INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) \"\\n\" \\\n            INCBIN_ALIGN_HOST \\\n            \".text\\n\" \\\n    ); \\\n    INCBIN_EXTERN(NAME)\n\n#endif\n#endif\n\n// -----------------------------------------------------------------------------\n"
  },
  {
    "path": "vault/c_once.c",
    "content": "#pragma once\n#define ONCE static int once##__LINE__=1; for(;once##__LINE__;once##__LINE__=0)\n\n/*\n#define once_unique(a) once_join(a, __LINE__)\n#define once_join(a,b) once_jo1n(a,b)\n#define once_jo1n(a,b) a##b\n\n#define ONCE \\\n    static int once_unique(once) = 0; for(; !once_unique(once); once_unique(once) = 1)\n*/\n\n/*\nint main() {\n    for( int i = 0; i < 10; ++i ) {\n        ONCE {\n            puts(\"hi\");\n        }\n    }\n}\n*/\n"
  },
  {
    "path": "vault/c_overload.c",
    "content": "// msvc trick to expand vargs properly by Braden Steffaniak\n// - see https://stackoverflow.com/a/24028231\n\n#pragma once\n#define GLUE(x, y) x y\n\n#define RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, count, ...) count\n#define EXPAND_ARGS(args) RETURN_ARG_COUNT args\n#define COUNT_ARGS_MAX5(...) EXPAND_ARGS((__VA_ARGS__, 5, 4, 3, 2, 1, 0))\n\n#define OVERLOAD_MACRO2(name, count) name##count\n#define OVERLOAD_MACRO1(name, count) OVERLOAD_MACRO2(name, count)\n#define OVERLOAD_MACRO(name, count) OVERLOAD_MACRO1(name, count)\n\n#define CALL_OVERLOAD(name, ...) GLUE(OVERLOAD_MACRO(name, COUNT_ARGS_MAX5(__VA_ARGS__)), (__VA_ARGS__))\n\n/* usage:\n#define ASSERT1(expr)             assert1(expr)\n#define ASSERT2(expr, errormsg)   assert2(expr, errormsg)\n#define ASSERT(...) CALL_OVERLOAD(ASSERT, __VA_ARGS__)\n*/\n"
  },
  {
    "path": "vault/c_plan.c",
    "content": "// PLAN is usually a TODO taskfile, like: AUTORUN { puts(\"[x] task1\"); puts(\"[ ] task2\"); }\n// Usage: cl test.c -DPLAN=\"^<my_plan.h^>\" or -DPLAN=\"\\\\\\\"my_plan.h\\\\\\\"\"\n\n#pragma once\n\n#if defined __has_include\n#  if __has_include(\"plan.c\")\n#    include \"plan.c\"\n#  endif\n#elif defined PLAN\n#  include PLAN\n#endif\n"
  },
  {
    "path": "vault/c_section.c",
    "content": "// - rlyeh, public domain\n\n#pragma once\n\n#ifndef _MSC_VER\n#define SECTION(name) __attribute__((section(\".\" #name \"#\")))\n#else\n#define SECTION(name) __declspec(allocate(\".\" #name))\n#endif\n"
  },
  {
    "path": "vault/c_thread.c",
    "content": "// - rlyeh, public domain\n\n#pragma once\n\n#if defined _MSC_VER || defined __TINYC__\n#define THREAD __declspec(thread)\n#else\n#define THREAD __thread\n#endif\n"
  },
  {
    "path": "vault/c_unreachable.c",
    "content": "// - rlyeh, public domain\n\n#pragma once\n\n#ifdef DEBUG\n#define UNREACHABLE() assert(!\"This line was not meant to be reached\")\n#elif defined( _MSC_VER )\n#define UNREACHABLE() __assume(0)\n#elif defined __GNUC__ // && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))\n#define UNREACHABLE() __builtin_unreachable()\n#else\n#define UNREACHABLE()\n#endif\n"
  },
  {
    "path": "vault/c_with.c",
    "content": "// - rlyeh, public domain\n\n#pragma once\n#define ON  1\n#define OFF 0\n#define WITH(x) ((x)+0)\n\n/*\n// cl c_with.c\n// cl c_with.c -DALSA\n// cl c_with.c -DALSA=ON\n// cl c_with.c -DALSA=OFF\n// cl c_with.c -DALSA=0\n// cl c_with.c -DALSA=1\n\nint main() {\n\t#if WITH(_MSC_VER)\n\tputs(\"msc\");\n\t#endif\n\t#if WITH(__GNUC__)\n\tputs(\"gcc\");\n\t#endif\n\t#if WITH(ALSA)\n\tputs(\"alsa audio\");\n\t#endif\n\t#if WITH(_WIN32)\n\tputs(\"win32\");\n\t#endif\n}\n*/\n"
  },
  {
    "path": "vault/ds.c",
    "content": "// [x] data structures: array, hash, map @todo: set, lfqueue, sort, comp,\n// - rlyeh, public domain\n\n#ifdef DS_C\n#define ALLOC_C\n#define HASH_C\n#define MAP_C\n#define QUARK_C\n#define STREAM_C\n#define FORMAT_C\n#define STRING_C\n#define SORT_C\n#define SET_C\n#define ROPE_C\n#endif\n\n#include \"os.c\"\n#include \"ds_hash.c\"\n#include \"ds_sort.c\"\n#include \"ds_array.c\"\n#include \"ds_alloc.c\"\n#include \"ds_map.c\"\n#include \"ds_set.c\"\n#include \"ds_stream.c\"\n#include \"ds_format.c\"\n#include \"ds_string.c\"\n#include \"ds_quark.c\"\n#include \"ds_rope.c\"\n"
  },
  {
    "path": "vault/ds_alloc.c",
    "content": "// [x] memory: realloc, vrealloc, stack\n// [ ] @todo: gc, pool, game mark/rewind+game stack |level|game|>---<stack|\n// - rlyeh, public domain\n\n#ifndef ALLOC_H\n#define ALLOC_H\n\n#define align_up(addr,N)   ((addr + (N - 1)) & -N)  // Round up to N-byte boundary\n#define align_down(addr,N) (addr & -N)  // Round down to a N-byte boundary\n\n// default allocator (aborts on out-of-mem)\nvoid*  xrealloc(void* p, size_t sz);\nsize_t xlen(void* p);\n\n// vector based allocator (x1.75 enlarge factor)\nvoid*  vrealloc(void* p, size_t sz);\nsize_t vlen(void* p);\n\n// stack based allocator (negative bytes will rewind stack, like when entering new frame)\nvoid*  stack(int bytes);\n\n#endif\n\n// vector ----------------------------------------------------------------------\n\n#ifdef ALLOC_C\n#pragma once\n\nvoid* vrealloc( void* p, size_t sz ) {\n    if( !sz ) {\n        if( p ) {\n            size_t *ret = (size_t*)p - 2;\n            ret[0] = 0;\n            ret[1] = 0;\n            REALLOC( ret, 0 );\n        }\n        return 0;\n    } else {\n        size_t *ret = (size_t*)p - 2;\n        if( !p ) {\n            ret = (size_t*)REALLOC( 0, sizeof(size_t) * 2 + sz );\n            ret[0] = sz;\n            ret[1] = 0;\n        } else {\n            size_t osz = ret[0];\n            size_t ocp = ret[1];\n            if( sz <= (osz + ocp) ) {\n                ret[0] = sz;\n                ret[1] = ocp - (sz - osz);\n            } else {\n                ret = (size_t*)REALLOC( ret, sizeof(size_t) * 2 + sz * 1.75 );\n                ret[0] = sz;\n                ret[1] = (size_t)(sz * 1.75) - sz;\n            }\n        }\n        return &ret[2];\n    }\n}\nsize_t vlen( void* p ) {\n    return p ? 0[ (size_t*)p - 2 ] : 0;\n}\n\n// realloc ---------------------------------------------------------------------\n\nvoid* xrealloc(void* ptr, size_t size) {\n    static void *oom_reserve = 0; if(!oom_reserve) oom_reserve = REALLOC(0, 4 * 1024 * 1024);\n    ptr = REALLOC(ptr, size);\n    if( !ptr && size ) {\n        REALLOC(oom_reserve, 0), oom_reserve = 0;\n        abort(); // exit( ENOMEM );\n    }\n#ifdef XREALLOC_POISON\n    if( ptr && size ) {\n        memset(ptr, 0xCD, size);\n    }\n#endif\n    return ptr;\n}\nsize_t xlen(void* p) {\n    if( p ) return MSIZE(p);\n    return 0;\n}\n\n// stack -----------------------------------------------------------------------\n\nvoid* stack(int bytes) { // use negative bytes to rewind stack\n    static __thread uint8_t *stack_mem = 0;\n    static __thread uint64_t stack_ptr = 0;\n    static __thread uint64_t stack_max = 0; // watch this var, in case you want to fine tune 4 MiB value below\n    if( bytes < 0 ) {\n        if( stack_ptr > stack_max ) stack_max = stack_ptr;\n        return (stack_ptr = 0), NULL;\n    }\n    if( !stack_mem ) stack_mem = xrealloc(stack_mem, xlen(stack_mem) + 4 * 1024 * 1024);\n    return &stack_mem[ (stack_ptr += bytes) - bytes ];\n}\n\n#endif\n"
  },
  {
    "path": "vault/ds_array.c",
    "content": "// array library --------------------------------------------------------------\n// - rlyeh, public domain\n\n#pragma once\n\n#ifdef __cplusplus\n#define array_cast(x) (decltype(x))\n#else\n#define array_cast(x) (void *)\n#endif\n\n#define array(t) t*\n#define array_init(t) ( (t) = 0 )\n#define array_resize(t, n) ( array_c_ = array_count(t), array_realloc_((t),(n)), ((n)>array_c_? memset(array_c_+(t),0,((n)-array_c_)*sizeof(0[t])) : (void*)0), (t) )\n#define array_push(t, ...) ( array_realloc_((t),array_count(t)+1), (t)[ array_count(t) - 1 ] = (__VA_ARGS__) )\n#define array_pop(t) ( array_realloc_((t), array_count(t)-1) )\n#define array_back(t) ( (t)[ array_count(t)-1 ] ) // ( (t) ? &(t)[ array_count(t)-1 ] : NULL )\n#define array_data(t) (t)\n#define array_at(t,i) (t[i])\n#define array_count(t) (int)( (t) ? array_vlen_(t) / sizeof(0[t]) : 0u )\n#define array_bytes(t) (int)( (t) ? array_vlen_(t) : 0u )\n#define array_sort(t, cmpfunc) qsort( t, array_count(t), sizeof(0[t]), cmpfunc )\n#define array_empty(t) ( !array_count(t) )\n#define array_free(t) array_clear(t)\nstatic __thread unsigned array_c_;\n\n#if 0 // original: no reserve support\n#define array_reserve(t, n) ((void)0) // not implemented\n#define array_clear(t) ( array_realloc_((t), 0), (t) = 0 )\n#define array_vlen_(t)  ( vlen(t) - 0 )\n#define array_realloc_(t,n)  ( (t) = array_cast(t) vrealloc((t), ((n)+0) * sizeof(0[t])) )\n#else // new: with reserve support (buggy still?)\n#define array_reserve(t, n) ( array_realloc_((t),(n)), array_realloc_((t),0) )\n#define array_clear(t) ( array_realloc_((t), -1), (t) = 0 ) // -1\n#define array_vlen_(t)  ( vlen(t) - sizeof(0[t]) ) // -1\n#define array_realloc_(t,n)  ( (t) = array_cast(t) vrealloc((t), ((n)+1) * sizeof(0[t])) ) // +1\n#endif\n\n#define array_reverse(t) \\\n    do if( array_count(t) ) { \\\n        for(int l = array_count(t), e = l-1, i = (array_push(t, 0[t]), 0); i <= e/2; ++i ) \\\n            { l[t] = i[t]; i[t] = (e-i)[t]; (e-i)[t] = l[t]; } \\\n        array_pop(t); \\\n    } while(0)\n\n//#define array_foreach2(t,val_t,v) \\\n//    for( val_t *v = &0[t]; v < (&0[t] + array_count(t)); ++v )\n\n//#define array_foreach(t, it) \\\n//    for( void *end__ = (it = &0[t]) + array_count(t); it != end__; ++it )\n\n#define array_foreach(t,val_t,v) \\\n    for( val_t *it__ = &0[t]; it__ < (&0[t] + array_count(t)); ++it__ ) \\\n        for( val_t v = *it__, *on__ = &v; on__; on__ = 0 )\n\n#define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \\\n    bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn )\n\n#define array_insert(t, i, n) do { \\\n    int ac = array_count(t); \\\n    if( i >= ac ) { \\\n        array_push(t, n); \\\n    } else { \\\n        array_push(t, array_back(t)); \\\n        memmove( &(t)[(i)+1], &(t)[i], (ac - (i)) * sizeof(t[0]) ); \\\n        (t)[ i ] = (n); \\\n    } \\\n} while(0)\n\n#define array_copy(t, src) do { /*todo: review old vrealloc call!*/ \\\n    array_free(t); \\\n    (t) = vrealloc( (t), array_count(src) * sizeof(0[t])); \\\n    memcpy( (t), src, array_count(src) * sizeof(0[t])); \\\n} while(0)\n\n#define array_erase(t, i) do { \\\n    memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \\\n    array_pop(t); \\\n} while(0)\n\n#define array_unique(t, cmpfunc) do { /*todo: review old vrealloc call!*/ \\\n    int cnt = array_count(t), dupes = 0; \\\n    if( cnt > 1 ) { \\\n        const void *prev = &(t)[0]; \\\n        array_sort(t, cmpfunc); \\\n        for( int i = 1; i < cnt; ) { \\\n            if( cmpfunc(&t[i], prev) == 0 ) { \\\n                memmove( &t[i], &t[i+1], (cnt - 1 - i) * sizeof(t[0]) ) ; \\\n                --cnt; \\\n                ++dupes; \\\n            } else { \\\n                prev = &(t)[i]; \\\n                ++i; \\\n            } \\\n        } \\\n        if( dupes ) { \\\n            (t) = vrealloc((t), (array_count(t) - dupes) * sizeof(0[t])); \\\n        } \\\n    } \\\n} while(0)\n"
  },
  {
    "path": "vault/ds_format.c",
    "content": "// format library\n// - rlyeh, public domain\n\n#ifndef FORMAT_H\n#define FORMAT_H\n#include <stdarg.h>\n\nchar*           vl(const char *fmt, va_list);\nchar*           va(const char *fmt, ...);\nint             is_va(const char *s);\n\n#define va(...) \\\n    (printf || printf(__VA_ARGS__), va(__VA_ARGS__))  // vs2015 check va trick\n#define vl(...) \\\n    (printf || vprintf(__VA_ARGS__), vl(__VA_ARGS__)) // this doesnt work afaik\n\n#endif\n\n// -----------------------------------------------------------------------------\n\n#ifdef FORMAT_C\n#pragma once\n\n#if defined _MSC_VER && !defined __thread\n#define __thread __declspec(thread)\n#endif\n\n#include <assert.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\nint is_va(const char *s) {\n    return (1&(uintptr_t)s) && s[-1] == 0;\n}\nchar* (vl)(const char *fmt, va_list vl) {\n    va_list copy;\n    va_copy(copy, vl);\n    int sz = vsnprintf( 0, 0, fmt, copy ) + 1;\n    va_end(copy);\n\n    int reqlen = sz + 1; // 1 for even padding\n\n    char* ptr;\n    enum { STACK_ALLOC = 16384 };\n    if( reqlen < STACK_ALLOC ) { // fit stack?\n        static __thread char buf[STACK_ALLOC+1];\n        static __thread int cur = 1, len = STACK_ALLOC;\n        ptr = buf + ((cur+reqlen) > len ? cur = 1 : (cur += reqlen) - reqlen);\n    } else { // else use heap (@fixme: single memleak per invoking thread)\n        static __thread char *buf = 0;\n        static __thread int cur = 1, len = -STACK_ALLOC;\n        if( reqlen >= len ) buf = realloc(buf, len = abs(len) * 1.75 + reqlen);\n        ptr = buf + ((cur+reqlen) > len ? cur = 1 : (cur += reqlen) - reqlen);\n    }\n\n    ptr += !(1&(uintptr_t)ptr); // align to even address only when already odd\n    ptr[-1] = 0; // add header\n    assert(is_va(ptr));\n\n    vsnprintf( ptr, sz, fmt, vl );\n    return (char *)ptr;\n}\nchar* (va)(const char *fmt, ...) {\n    va_list list;\n    va_start(list, fmt);\n    char *s = vl(fmt, list);\n    va_end(list);\n    return s;\n}\n\n// -----------------------------------------------------------------------------\n\n#ifdef FORMAT_DEMO\n#pragma once\nint main() {\n    char *x = va(\"hello %d\", 123); \n    puts(x);}\n#define main main__\n#endif // FORMAT_DEMO\n#endif // FORMAT_C\n"
  },
  {
    "path": "vault/ds_hash.c",
    "content": "// hash ------------------------------------------------------------------------\n// - rlyeh, public domain\n\nuint64_t hash_int(int key);\nuint64_t hash_flt(double dbl);\nuint64_t hash_u64(uint64_t key);\nuint64_t hash_str(const char* str);\nuint64_t hash_ptr(const void* ptr);\nuint64_t hash_vec2(const float pt[2]);\nuint64_t hash_vec3(const float pt[3]);\nuint64_t hash_vec4(const float pt[4]);\n\n// compile time string hash (pure C) -------------------------------------------\n// Based on code by http://lolengine.net/blog/2011/12/20/cpp-constant-string-hash\n// This macro is not always inlined. Depends on compilers and optimization flags.\n// For example g++ requires -O3 and msvc requires /O2 (verify output assembly with /Fa).\n// About the hash function, it is using my own and free hashing algorithm:\n// a few more collisions than FNV1A64 (faster though).\n// - rlyeh, public domain.\n#ifndef HASH_STR\n#define HASH_STR(str)                  HASH_STR64(0,131ull,str,0)\n#define HASH_STR64(hsh,mul,str,idx)    HASH_STR16(HASH_STR16(HASH_STR16(HASH_STR16(hsh,mul,str,idx+48),mul,str,idx+32),mul,str,idx+16),mul,str,idx)\n#define HASH_STR16(hsh,mul,str,idx)    HASH_STR04(HASH_STR04(HASH_STR04(HASH_STR04(hsh,mul,str,idx+12),mul,str,idx+ 8),mul,str,idx+ 4),mul,str,idx)\n#define HASH_STR04(hsh,mul,str,idx)    HASH_STR01(HASH_STR01(HASH_STR01(HASH_STR01(hsh,mul,str,idx+ 3),mul,str,idx+ 2),mul,str,idx+ 1),mul,str,idx)\n#define HASH_STR01(hsh,mul,str,idx)    ((HASH_STRCHR(str,idx) ^ hsh) * mul)\n#define HASH_STRCHR(str,idx)           ((unsigned)str[(idx)<HASH_STRLEN(str)?HASH_STRLEN(str)-1-(idx):HASH_STRLEN(str)])\n#define HASH_STRLEN(str)               (sizeof(str)-1)\n#endif\n\n\n\n#ifdef HASH_C\n#pragma once\n\n// { Thomas Mueller at https://stackoverflow.com/questions/664014/ - says no collisions for 32bits!\n\nuint32_t hash32(uint32_t x) {\n    x = ((x >> 16) ^ x) * 0x45d9f3b;\n    x = ((x >> 16) ^ x) * 0x45d9f3b;\n    x = (x >> 16) ^ x;\n    return x;\n}\n\nuint32_t unhash32(uint32_t x) {\n    x = ((x >> 16) ^ x) * 0x119de1f3;\n    x = ((x >> 16) ^ x) * 0x119de1f3;\n    x = (x >> 16) ^ x;\n    return x;\n}\n\nuint64_t hash64(uint64_t x) {\n    x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);\n    x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);\n    x = x ^ (x >> 31);\n    return x;\n}\n/*\nuint32_t hash64(uint64_t v) {\n    uint32_t hi = v >> 32;\n    uint32_t lo = v & 0xFFFFFFFF; // (uint32_t)-1;\n    return triple32(hi) ^ triple32(lo);\n}\n*/\n\nuint64_t unhash64(uint64_t x) {\n    x = (x ^ (x >> 31) ^ (x >> 62)) * UINT64_C(0x319642b2d24d8ec3);\n    x = (x ^ (x >> 27) ^ (x >> 54)) * UINT64_C(0x96de1b173f119089);\n    x = x ^ (x >> 30) ^ (x >> 60);\n    return x;\n}\n\n// } Thomas Mueller\n\nuint64_t hash_triple32(uint32_t x) { \n    // triple32 hashing (unlicensed) https://github.com/skeeto/hash-prospector\n    // exact bias: 0.020888578919738908\n    x ^= x >> 17;\n    x *= UINT32_C(0xed5ad4bb);\n    x ^= x >> 11;\n    x *= UINT32_C(0xac4c1b51);\n    x ^= x >> 15;\n    x *= UINT32_C(0x31848bab);\n    x ^= x >> 14;\n    return x;\n}\nuint64_t hash_untriple32(uint32_t x) {\n    x ^= x >> 14 ^ x >> 28;\n    x *= UINT32_C(0x32b21703);\n    x ^= x >> 15 ^ x >> 30;\n    x *= UINT32_C(0x469e0db1);\n    x ^= x >> 11 ^ x >> 22;\n    x *= UINT32_C(0x79a85073);\n    x ^= x >> 17;\n    return x;\n}\n\nuint64_t hash_mix64(uint64_t key) {\n    // Thomas Wang's 64bit Mix Function (public domain) http://www.cris.com/~Ttwang/tech/inthash.htm\n    key += ~(key << 32);\n    key ^=  (key >> 22);\n    key += ~(key << 13);\n    key ^=  (key >>  8);\n    key +=  (key <<  3);\n    key ^=  (key >> 15);\n    key += ~(key << 27);\n    key ^=  (key >> 31);\n    return key;\n}\n\nuint64_t hash_int(int key) {\n    // return hash64((uint64_t)key);\n    // return hash_mix64((uint64_t)key);\n    // return hash_triple32((uint32_t)key);\n    return hash32((uint32_t)key);\n}\n\nuint64_t hash_u64(uint64_t key) {\n    // return hash_mix64(key);\n    return hash64(key);\n}\n\n// ---\n\nuint64_t hash_ptr(const void *ptr) {\n    uint64_t key = (uint64_t)(uintptr_t)ptr;\n    return hash_u64(key >> 3); // >> 4? needed?\n}\n\nuint64_t hash_flt(double dbl) {\n    union { uint64_t i; double d; } u; u.d = dbl;\n    return hash_u64( u.i );\n}\n\nuint64_t hash_vec2(const float v2[2]) {\n    return hash_flt(v2[0]) ^ hash_flt(v2[1]);\n}\n\nuint64_t hash_vec3(const float v3[3]) {\n    return hash_flt(v3[0]) ^ hash_flt(v3[1]) ^ hash_flt(v3[2]);\n}\n\nuint64_t hash_vec4(const float v4[4]) {\n    return hash_flt(v4[0]) ^ hash_flt(v4[1]) ^ hash_flt(v4[2]) ^ hash_flt(v4[3]);\n}\n\nuint64_t hash_str(const char* str) {\n    // faster than fnv1a, a few more collisions though.\n    uint64_t hash = 0; // fnv1a: 14695981039346656037ULL;\n    while( *str ) {\n        hash = ( (unsigned char)*str++ ^ hash ) * 131; // fnv1a: 0x100000001b3ULL;\n    }\n    return hash;\n}\n\n#ifdef HASH_DEMO\n#include <stdio.h>\nint main() {\n    uint64_t literal = (uint64_t)0xf0e28e9bdecd6646ull;\n    printf(\"%016llx\\n\", literal);\n\n    uint64_t precomp = (uint64_t)STRHASH(\"/hello/world.txt\");\n    printf(\"%016llx\\n\", precomp);\n\n    uint64_t runtime = (uint64_t)strhash(\"/hello/world.txt\");\n    printf(\"%016llx\\n\", runtime);\n}\n#define main __main\n#endif // HASH_DEMO\n#endif // HASH_C\n"
  },
  {
    "path": "vault/ds_map.c",
    "content": "// generic map<K,V> container.\n// ideas from: https://en.wikipedia.org/wiki/Hash_table\n// ideas from: https://probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable/\n// ideas from: http://www.idryman.org/blog/2017/05/03/writing-a-damn-fast-hash-table-with-tiny-memory-footprints/\n// - rlyeh, public domain.\n\n#ifndef MAP_H\n#define MAP_H\n\n#include <stdint.h>\n#include <stdbool.h>\n\n// config\n#ifndef MAP_REALLOC\n#define MAP_REALLOC REALLOC\n#endif\n#ifndef MAP_HASHSIZE\n#define MAP_HASHSIZE (4096 << 4)\n#endif\n#ifndef MAP_DONT_ERASE\n#define MAP_DONT_ERASE 1\n#endif\n\n// public api\n#define map(K,V) \\\n    struct { map base; struct { pair p; K key; V val; } tmp, *ptr; V* tmpval; \\\n        int (*typed_cmp)(K, K); uint64_t (*typed_hash)(K); } *\n\n#define map_init(m, cmpfn, hashfn) ( \\\n    (m) = map_cast((m)) MAP_REALLOC(0, sizeof(*(m))), \\\n    map_init(&(m)->base), \\\n    (m)->base.cmp = (int(*)(void*,void*))( (m)->typed_cmp = map_cast((m)->typed_cmp) cmpfn), \\\n    (m)->base.hash = (uint64_t(*)(void*))( (m)->typed_hash = map_cast((m)->typed_hash) hashfn ) \\\n    )\n\n#define map_free(m) ( \\\n    map_free(&(m)->base), \\\n    MAP_REALLOC((m), sizeof(*(m))), (m) = 0 \\\n    )\n\n#define map_insert(m, k, v) ( \\\n    (m)->ptr = map_cast((m)->ptr) MAP_REALLOC(0, sizeof((m)->tmp)), \\\n    (m)->ptr->val = (v), \\\n    (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \\\n    map_insert(&(m)->base, &(m)->ptr->p, &(m)->ptr->key, &(m)->ptr->val, (m)->ptr->p.keyhash, (m)->ptr), \\\n    &(m)->ptr->val \\\n    )\n\n#define map_find(m, k) ( \\\n    (m)->ptr = &(m)->tmp, \\\n    (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \\\n    (m)->ptr = map_cast((m)->ptr) map_find(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash), \\\n    (m)->ptr ? &(m)->ptr->val : 0 \\\n    )\n\n#define map_erase(m, k) ( \\\n    (m)->ptr = &(m)->tmp, \\\n    (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \\\n    map_erase(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash) \\\n    )\n\n#define map_foreach(m,key_t,k,val_t,v) \\\n    for( int i_ = 0; i_ < MAP_HASHSIZE; ++i_) \\\n        for( pair *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \\\n            for( key_t k = *(key_t *)cur_->key; on_; ) \\\n                for( val_t v = *(val_t *)cur_->value; on_; on_ = 0 )\n\n#define map_clear(m) ( \\\n    map_clear(&(m)->base) \\\n    )\n\n#define map_count(m)        map_count(&(m)->base)\n#define map_gc(m)           map_gc(&(m)->base)\n\n// private:\n\n#ifdef __cplusplus\n#define map_cast(t) (decltype(t))\n#else\n#define map_cast(t) (void *)\n#endif\n\ntypedef struct pair {\n    struct pair *next;\n\n    uint64_t keyhash;\n    void *key;\n    void *value;\n    void *super;\n} pair;\n\ntypedef struct map {\n    array(pair*) array;\n    int (*cmp)(void *, void *);\n    uint64_t (*hash)(void *);\n} map;\n\nvoid  (map_init)(map *m);\nvoid  (map_free)(map *m);\n\nvoid  (map_insert)(map *m, pair *p, void *key, void *value, uint64_t keyhash, void *super);\nvoid  (map_erase)(map *m, void *key, uint64_t keyhash);\nvoid* (map_find)(map *m, void *key, uint64_t keyhash);\nint   (map_count)(map *m);\nvoid  (map_gc)(map *m); // only if using MAP_DONT_ERASE\n\n#endif\n\n// -------------------------------\n\n#if defined MAP_C || defined MAP_DEMO\n#pragma once\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <string.h>\n\nenum { MAP_GC_SLOT = MAP_HASHSIZE };\ntypedef int map_is_pow2_assert[ !(MAP_HASHSIZE & (MAP_HASHSIZE - 1)) ];\n\nstatic int map_get_index(uint64_t hkey1) {\n    return hkey1 & (MAP_HASHSIZE-1);\n}\n\nvoid (map_init)(map* m) {\n    map c = {0};\n    *m = c;\n\n    array_resize(m->array, (MAP_HASHSIZE+1));\nmemset(m->array, 0, (MAP_HASHSIZE+1) * sizeof(m->array[0]) ); // array_resize() just did memset()\n}\n\nvoid (map_insert)(map* m, pair *p, void *key, void *value, uint64_t keyhash, void *super) {\n    p->keyhash = keyhash;\n    p->key = key;\n    p->value = value;\n    p->super = super;\n\n    /* Insert onto the beginning of the list */\n    int index = map_get_index(p->keyhash);\n    p->next = m->array[index];\n    m->array[index] = p;\n}\n\nvoid* (map_find)(map* m, void *key, uint64_t keyhash) {\n    int index = map_get_index(keyhash);\n    for( pair *cur = m->array[index]; cur; cur = cur->next ) {\n        if( cur->keyhash == keyhash ) {\n            char **c = (char **)cur->key;\n            char **k = (char **)key;\n            if( !m->cmp(c[0], k[0]) ) {\n                return cur->super;\n            }\n        }\n    }\n    return 0;\n}\n\nvoid (map_erase)(map* m, void *key, uint64_t keyhash) {\n    int index = map_get_index(keyhash);\n    for( pair *prev = 0, *cur = m->array[index]; cur; (prev = cur), (cur = cur->next) ) {\n        if( cur->keyhash == keyhash ) {\n            char **c = (char **)cur->key;\n            char **k = (char **)key;\n            if( !m->cmp(c[0], k[0]) ) {\n                if( prev ) prev->next = cur->next; else m->array[index] = cur->next ? cur->next : 0;\n#if MAP_DONT_ERASE\n                /* Insert onto the beginning of the GC list */\n                cur->next = m->array[MAP_GC_SLOT];\n                m->array[MAP_GC_SLOT] = cur;\n#else\n                MAP_REALLOC(cur,0);\n#endif\n                return;\n            }\n        }\n    }\n}\n\nint (map_count)(map* m) {\n    int counter = 0;\n    for( int i = 0; i < MAP_HASHSIZE; ++i) {\n        for( pair *cur = m->array[i]; cur; cur = cur->next ) {\n            ++counter;\n        }\n    }\n    return counter;\n}\n\nvoid (map_gc)(map* m) {\n#if MAP_DONT_ERASE\n    for( pair *next, *cur = m->array[MAP_GC_SLOT]; cur; cur = next ) {\n        next = cur->next;\n        MAP_REALLOC(cur,0);\n    }\n    m->array[MAP_GC_SLOT] = 0;\n#endif\n}\n\nvoid (map_clear)(map* m) {\n    for( int i = 0; i <= MAP_HASHSIZE; ++i) {\n        for( pair *next, *cur = m->array[i]; cur; cur = next ) {\n            next = cur->next;\n            MAP_REALLOC(cur,0);\n        }\n        m->array[i] = 0;\n    }\n}\n\nvoid (map_free)(map* m) {\n    (map_clear)(m);\n\n    array_free(m->array);\n    m->array = 0;\n\n    map c = {0};\n    *m = c;\n}\n\n// -------------------------------\n\n#ifdef MAP_DEMO\n#include <stdio.h>\n#include <time.h>\n#ifdef __cplusplus\n#include <unordered_map>\n#include <map>\n#endif\n\n#ifdef NDEBUG\n#undef NDEBUG\n#include <assert.h>\n#define NDEBUG\n#else\n#include <assert.h>\n#endif\n\nvoid map_benchmark() {\n    #ifndef M\n    #define M 100\n    #endif\n    #ifndef N\n    #define N 50000\n    #endif\n    #define BENCH(CREATE,COUNT,INSERT,FIND,ITERATE,ERASE,DESTROY) do { \\\n        static char **bufs = 0; \\\n        if(!bufs) { \\\n            bufs = (char **)MAP_REALLOC(0, sizeof(char*) * N ); \\\n            for( int i = 0; i < N; ++i ) { \\\n                bufs[i] = (char*)MAP_REALLOC(0, 16); \\\n                sprintf(bufs[i], \"%d\", i); \\\n            } \\\n        } \\\n        clock_t t0 = clock(); \\\n        for( int i = 0; i < M; ++i ) { \\\n            CREATE; \\\n            if(i==0) printf(\"CREATE:%d \", (int)COUNT), fflush(stdout); \\\n            for( int j = 0; j < N; ++j ) { \\\n                char *buf = bufs[j]; \\\n                INSERT; \\\n            } \\\n            if(i==0) printf(\"INSERT:%d \", (int)COUNT), fflush(stdout); \\\n            for( int j = 0; j < N; ++j ) { \\\n                char *buf = bufs[j]; \\\n                FIND; \\\n            } \\\n            if(i==0) printf(\"FIND:%d \", (int)COUNT), fflush(stdout); \\\n            ITERATE; \\\n            if(i==0) printf(\"ITERATE:%d \", (int)COUNT), fflush(stdout); \\\n            for( int j = 0; j < N; ++j ) { \\\n                char *buf = bufs[j]; \\\n                ERASE; \\\n            } \\\n            if(i==0) printf(\"REMOVE:%d \", (int)COUNT), fflush(stdout); \\\n            DESTROY; \\\n            if(i==0) printf(\"DESTROY%s\", \" \"); \\\n        } \\\n        clock_t t1 = clock(); \\\n        double t = (t1 - t0) / (double)CLOCKS_PER_SEC; \\\n        int ops = (M*N)*6; \\\n        printf(\"%d ops in %fs = %.2fM ops/s (\" #CREATE \")\\n\", ops, t, ops / (t * 1e6)); \\\n    } while(0)\n\n    map(char*,int) m = 0;\n    BENCH(\n        map_init(m, sort_str, hash_str),\n        map_count(m),\n        map_insert(m, buf, i),\n        map_find(m, buf),\n        map_foreach(m,char*,k,int,v) {},\n        map_erase(m, buf),\n        map_free(m)\n    );\n\n#ifdef __cplusplus\n    using std_map = std::map<const char *,int>;\n    BENCH(\n        std_map v,\n        v.size(),\n        v.insert(std::make_pair(buf, i)),\n        v.find(buf),\n        for( auto &kv : v ) {},\n        v.erase(buf),\n        {}\n    );\n\n    using std_unordered_map = std::unordered_map<const char *,int>;\n    BENCH(\n        std_unordered_map v,\n        v.size(),\n        v.insert(std::make_pair(buf, i)),\n        v.find(buf),\n        for( auto &kv : v ) {},\n        v.erase(buf),\n        {}\n    );\n#endif\n#undef N\n#undef M\n}\n\nvoid map_tests() {\n    {\n        map(int,char*) m = 0;\n        map_init(m, sort_int, hash_int);\n            assert( 0 == map_count(m) );\n        map_insert(m, 123, \"123\");\n        map_insert(m, 456, \"456\");\n            assert( 2 == map_count(m) );\n            assert( map_find(m, 123) );\n            assert( map_find(m, 456) );\n            assert(!map_find(m, 789) );\n            assert( 0 == strcmp(\"123\", *map_find(m, 123)) );\n            assert( 0 == strcmp(\"456\", *map_find(m, 456)) );\n\n        map_foreach(m,const int,k,char*,v) {\n            printf(\"%d->%s\\n\", k, v);\n        }\n\n        map_erase(m, 123);\n            assert(!map_find(m, 123) );\n            assert( 1 == map_count(m) );\n        map_erase(m, 456);\n            assert(!map_find(m, 456) );\n            assert( 0 == map_count(m) );\n        map_free(m);\n    }\n\n    {\n        map(char*,int) m = 0;\n        map_init(m, sort_str, hash_str);\n            assert( map_count(m) == 0 );\n        map_insert(m, \"123\", 123);\n        map_insert(m, \"456\", 456);\n            assert( map_count(m) == 2 );\n            assert( map_find(m,\"123\") );\n            assert( map_find(m,\"456\") );\n            assert(!map_find(m,\"789\") );\n\n        map_foreach(m,const char *,k,int,v) {\n            printf(\"%s->%d\\n\", k, v);\n        }\n\n        map_erase(m, \"123\");\n            assert( 456 == *map_find(m,\"456\") );\n            assert( map_count(m) == 1 );\n        map_erase(m, \"456\");\n            assert( map_count(m) == 0 );\n        map_free(m);\n\n        assert(!puts(\"Ok\"));\n    }\n}\n\nvoid map_tests2() {\n    map(char*,double) m = 0;\n\n    map_init(m, sort_str, hash_str);\n\n    map_insert(m, \"hello\", 101.1);\n    map_insert(m, \"world\", 102.2);\n    map_insert(m, \"nice\", 103.3);\n    map_insert(m, \"hash\", 104.4);\n\n    assert(!map_find(m, \"random\"));\n\n    assert(map_find(m, \"hello\"));\n    assert(map_find(m, \"world\"));\n    assert(map_find(m, \"nice\") );\n    assert(map_find(m, \"hash\") );\n\n    assert( 101.1 == *map_find(m, \"hello\"));\n    assert( 102.2 == *map_find(m, \"world\"));\n    assert( 103.3 == *map_find(m, \"nice\"));\n    assert( 104.4 == *map_find(m, \"hash\"));\n\n    // reinsertion\n    assert(map_insert(m, \"hello\", -101.1));\n    assert(-101.1 == *map_find(m, \"hello\"));\n\n    map_foreach(m,char*,k,double,v) {\n        printf(\"%s -> %f\\n\", k, v);\n    }\n\n    map_free(m);\n\n    assert( !puts(\"Ok\") );\n}\n\nvoid map_benchmark2() {\n    #ifndef NUM\n    #define NUM 2000000\n    #endif\n\n    map(int,int) m = 0;\n    map_init(m, sort_int, hash_int);\n\n    clock_t t0 = clock();\n\n    for( int i = 0; i < NUM; ++i ) {\n        map_insert(m, i, i+1);\n    }\n    for( int i = 0; i < NUM; ++i ) {\n        uint32_t *v = map_find(m, i);\n        assert( v && *v == i + 1 );\n    }\n\n    double t = (clock() - t0) / (double)CLOCKS_PER_SEC;\n\n    printf(\"[0]=%d\\n\", *map_find(m, 0));\n    printf(\"[N-1]=%d\\n\", *map_find(m, NUM-1));\n    printf(\"%d ops in %5.3fs = %fM ops/s\\n\", (NUM*2), t, (NUM*2) / (1e6 * t) );\n\n    map_free(m);\n}\n\nint main() {\n    map_tests();\n    puts(\"---\");\n    map_tests2();\n    puts(\"---\");\n    map_benchmark();\n    puts(\"---\");\n    map_benchmark2();\n    assert(~puts(\"Ok\"));\n}\n\n#define main main__\n#endif // MAP_DEMO\n#endif // MAP_C\n"
  },
  {
    "path": "vault/ds_quark.c",
    "content": "// quarks ----------------------------------------------------------------------\n// - rlyeh, public domain\n\n#ifndef QUARK_H\n#define QUARK_H\n\ntypedef unsigned quark;\n\nquark quark_intern(char *s);\nchar* quark_str(quark q);\nint   quark_len(quark q);\nint   quark_hash(quark q);\nint   quark_cmp(quark a, quark b);\n\n#define quark_intern(__VA_ARGS__) quark_intern(va(__VA_ARGS__))\n\n#endif\n\n// -----------------------------------------------------------------------------\n\n#ifdef QUARK_C\n#pragma once\n\ntypedef struct quark_dictionary {\n    char *block;\n    uint64_t block_used;\n    array(char*) strings;\n    unsigned index;\n} quark_dictionary;\n\nstatic __thread quark_dictionary qd = {0};\n\nquark (quark_intern)(char *s) {\n    if( !qd.block ) qd.block = REALLOC(0, 4 * 1024 * 1024 ); // \n    uint64_t n = strlen(s) + 1;\n    array_push(qd.strings, qd.block + qd.block_used + 4);\n    memcpy(qd.block + qd.block_used, s - 4, n + 4);\n    qd.block_used += n + 4;\n    return ++qd.index;\n}\nchar *quark_str(quark q) {\n    return q > 0 && q <= qd.index ? qd.strings[ q - 1 ] : \"\";\n}\nint quark_len(quark q) {\n    return strlen(quark_str(q));\n}\nint quark_hash(quark q) {\n    return strhash(quark_str(q));\n}\nint quark_cmp(quark q1, quark q2) {\n    return strcmp(quark_str(q1), quark_str(q2));\n}\n\n#endif\n"
  },
  {
    "path": "vault/ds_rope.c",
    "content": "#ifndef ROPE_H\n#define ROPE_H\n\ntypedef struct rope rope;\n\nvoid rope_init( rope *s, int reserve, float grow );\nvoid rope_append( rope *s, const char *buf, int len );\nvoid rope_dump( rope *s );\nint rope_len( rope *s );\n\n#endif\n\n#ifdef ROPE_C\n#pragma once\n#include <stdint.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nstruct rope {\n    struct rope *root;\n    struct rope *next;\n    int len, cap;\n    float grow;\n    unsigned char *data;\n    // unsigned char data[rope_BLOCKSIZE - sizeof(rope*)*2 - sizeof(int)*2 )];\n};\n\nvoid rope_init( rope *s, int reserve, float grow ) {\n    memset(s, 0, sizeof(rope));\n    s->grow = grow;\n    s->data = realloc( s->data, (s->len = 0, s->cap = reserve) );\n}\n\nvoid rope_append( rope *s, const char *buf, int len ) {\n    while( s->next ) s = s->next;\n    if( len > 0 && s->cap > 0 ) {\n        int max = len > s->cap ? s->cap : len;\n        memcpy(s->data + s->len, buf, max);\n        s->len += max;\n        s->cap -= max;\n        buf += max;\n        len -= max;\n    }\n    if( len > 0 ) {\n        s->next = malloc( sizeof(rope) );\n        // linear (no decimals) or incremental (decimals)\n        rope_init( s->next, (s->grow - (int)s->grow) > 0 ? (len+1) * s->grow : s->grow, s->grow );\n        rope_append( s->next, buf, len );\n    }\n}\n\nvoid rope_dump( rope *s ) {\n    puts(\"--\");\n    for( ; s ; s = s->next ) {\n        printf(\"%03d/%03d bytes: \\\"%.*s\\\"\\n\", s->len, s->cap + s->len, s->len, s->data);\n    }\n}\n\nint rope_len( rope *s ) {\n    int len = 0;\n    for( ; s ; s = s->next ) {\n        len += s->len;\n    }\n    return len;\n}\n\n#ifdef ROPE_DEMO\nint main() {\n    rope s;\n    rope_init(&s, 5, 5); // 1.75); // 1.75f);\n    rope_dump(&s);\n\n    rope_append(&s, \"hello world.\", 12);\n    rope_dump(&s);\n\n    rope_append(&s, \"there's a lady who's sure all that glitter's gold.\", 50);\n    rope_dump(&s);\n\n    printf(\"%d bytes\\n\", rope_len(&s));\n}\n#define main main__\n#endif // ROPE_DEMO\n#endif // ROPE_C\n"
  },
  {
    "path": "vault/ds_set.c",
    "content": "// generic set<K> container.\n// ideas from: https://en.wikipedia.org/wiki/Hash_table\n// ideas from: https://probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable/\n// ideas from: http://www.idryman.org/blog/2017/05/03/writing-a-damn-fast-hash-table-with-tiny-memory-footprints/\n// - rlyeh, public domain.\n\n#ifndef SET_H\n#define SET_H\n\n#include <stdint.h>\n#include <stdbool.h>\n\n// config\n#ifndef SET_REALLOC\n#define SET_REALLOC REALLOC\n#endif\n#ifndef SET_HASHSIZE\n#define SET_HASHSIZE (4096 << 4)\n#endif\n#ifndef SET_DONT_ERASE\n#define SET_DONT_ERASE 1\n#endif\n\n// public api\n#define set(K) \\\n    struct { set base; struct { set_item p; K key; } tmp, *ptr; \\\n        int (*typed_cmp)(K, K); uint64_t (*typed_hash)(K); } *\n\n#define set_init(m, cmpfn, hashfn) ( \\\n    (m) = REALLOC(0, sizeof(*m)), \\\n    set_init(&(m)->base), \\\n    (m)->base.cmp = (int(*)(void*,void*))( (m)->typed_cmp = cmpfn), \\\n    (m)->base.hash = (uint64_t(*)(void*))( (m)->typed_hash = hashfn ) \\\n    )\n\n#define set_free(m) ( \\\n    set_clear(m), \\\n    set_free(&(m)->base), \\\n    (m) = REALLOC((m), 0), \\\n    (m) = 0 \\\n    )\n\n#define set_insert(m, k) ( \\\n    (m)->ptr = set_cast((m)->ptr) SET_REALLOC(0, sizeof((m)->tmp)), \\\n    (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \\\n    set_insert(&(m)->base, &(m)->ptr->p, &(m)->ptr->key, (m)->ptr->p.keyhash, (m)->ptr), \\\n    &(m)->ptr->key \\\n    )\n\n#define set_find(m, k) ( \\\n    (m)->ptr = &(m)->tmp, \\\n    (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \\\n    (m)->ptr = set_cast((m)->ptr) set_find(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash), \\\n    (m)->ptr ? &(m)->ptr->key : 0 \\\n    )\n\n#define set_erase(m, k) ( \\\n    (m)->ptr = &(m)->tmp, \\\n    (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \\\n    set_erase(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash) \\\n    )\n\n#define set_foreach(m,key_t,k) \\\n    for( int i_ = 0; i_ < SET_HASHSIZE; ++i_) \\\n        for( set_item *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \\\n            for( key_t k = *(key_t *)cur_->key; on_; on_ = 0 )\n\n#define set_clear(m) ( \\\n    set_clear(&(m)->base) \\\n    )\n\n#define set_count(m)        set_count(&(m)->base)\n#define set_gc(m)           set_gc(&(m)->base)\n\n// private:\n\n#ifdef __cplusplus\n#define set_cast(t) (decltype(t))\n#else\n#define set_cast(t) (void *)\n#endif\n\ntypedef struct set_item {\n    struct set_item *next;\n\n    uint64_t keyhash;\n    void *key;\n    void *super;\n} set_item;\n\ntypedef struct set {\n    array(set_item*) array;\n    int (*cmp)(void *, void *);\n    uint64_t (*hash)(void *);\n} set;\n\nvoid  (set_init)(set *m);\nvoid  (set_free)(set *m);\n\nvoid  (set_insert)(set *m, set_item *p, void *key, uint64_t keyhash, void *super);\nvoid  (set_erase)(set *m, void *key, uint64_t keyhash);\nvoid* (set_find)(const set *m, void *key, uint64_t keyhash);\nint   (set_count)(const set *m);\nvoid  (set_gc)(set *m); // only if using SET_DONT_ERASE\n\n#endif\n\n// -------------------------------\n\n#ifdef SET_C\n#pragma once\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <string.h>\n\nenum { set_GC_SLOT = SET_HASHSIZE };\ntypedef int set_is_pow2_assert[ !(SET_HASHSIZE & (SET_HASHSIZE - 1)) ];\n\nstatic int set_get_index(uint64_t hkey1) {\n    return hkey1 & (SET_HASHSIZE-1);\n}\n\nvoid (set_init)(set* m) {\n    set zero = {0};\n    *m = zero;\n\n    array_resize(m->array, (SET_HASHSIZE+1));\nmemset(m->array, 0, (SET_HASHSIZE+1) * sizeof(m->array[0]) ); // array_resize() just did memset()\n}\n\nvoid (set_insert)(set* m, set_item *p, void *key, uint64_t keyhash, void *super) {\n    p->keyhash = keyhash;\n    p->key = key;\n    p->super = super;\n\n    /* Insert onto the beginning of the list */\n    int index = set_get_index(p->keyhash);\n    p->next = m->array[index];\n    m->array[index] = p;\n}\n\nvoid* (set_find)(const set* m, void *key, uint64_t keyhash) {\n    int index = set_get_index(keyhash);\n    for( const set_item *cur = m->array[index]; cur; cur = cur->next ) {\n        if( cur->keyhash == keyhash ) {\n            char **c = (char **)cur->key;\n            char **k = (char **)key;\n            if( !m->cmp(c[0], k[0]) ) {\n                return cur->super;\n            }\n        }\n    }\n    return 0;\n}\n\nvoid (set_erase)(set* m, void *key, uint64_t keyhash) {\n    int index = set_get_index(keyhash);\n    for( set_item *prev = 0, *cur = m->array[index]; cur; (prev = cur), (cur = cur->next) ) {\n        if( cur->keyhash == keyhash ) {\n            char **c = (char **)cur->key;\n            char **k = (char **)key;\n            if( !m->cmp(c[0], k[0]) ) {\n                if (prev) prev->next = cur->next; else m->array[index] = cur->next ? cur->next : 0;\n#if SET_DONT_ERASE\n                /* Insert onto the beginning of the GC list */\n                cur->next = m->array[set_GC_SLOT];\n                m->array[set_GC_SLOT] = cur;\n#else\n                SET_REALLOC(cur,0);\n#endif\n                return;\n            }\n        }\n    }\n}\n\nint (set_count)(const set* m) { // does not include GC_SLOT\n    int counter = 0;\n    for( int i = 0; i < SET_HASHSIZE; ++i) {\n        for( const set_item *cur = m->array[i]; cur; cur = cur->next ) {\n            ++counter;\n        }\n    }\n    return counter;\n}\n\nvoid (set_gc)(set* m) { // clean deferred GC_SLOT only\n#if SET_DONT_ERASE\n    for( set_item *next, *cur = m->array[set_GC_SLOT]; cur; cur = next ) {\n        next = cur->next;\n        SET_REALLOC(cur,0);\n    }\n    m->array[set_GC_SLOT] = 0;\n#endif\n}\n\nvoid (set_clear)(set* m) { // include GC_SLOT\n    for( int i = 0; i <= SET_HASHSIZE; ++i) {\n        for( set_item *next, *cur = m->array[i]; cur; cur = next ) {\n            next = cur->next;\n            SET_REALLOC(cur,0);\n        }\n        m->array[i] = 0;\n    }\n}\n\nvoid (set_free)(set* m) {\n    (set_clear)(m);\n\n    array_free(m->array);\n    m->array = 0;\n\n    set zero = {0};\n    *m = zero;\n}\n\n// -------------------------------\n\n#ifdef SET_DEMO\n#include <stdio.h>\n#include <time.h>\n\n#ifdef NDEBUG\n#undef NDEBUG\n#include <assert.h>\n#define NDEBUG\n#else\n#include <assert.h>\n#endif\n\nvoid set_tests() {\n    {\n        set(int) m = {0};\n        set_init(&m, cmp_int, hash_int);\n            assert( 0 == set_count(&m) );\n        set_insert(&m, 123);\n        set_insert(&m, 456);\n            assert( 2 == set_count(&m) );\n            assert( set_find(&m, 123) );\n            assert( set_find(&m, 456) );\n            assert(!set_find(&m, 789) );\n            assert( 123 == *set_find(&m, 123) );\n            assert( 456 == *set_find(&m, 456) );\n\n        set_foreach(&m,const int,k) {\n            printf(\"%d\\n\", k);\n        }\n\n        set_erase(&m, 123);\n            assert(!set_find(&m, 123) );\n            assert( 1 == set_count(&m) );\n        set_erase(&m, 456);\n            assert(!set_find(&m, 456) );\n            assert( 0 == set_count(&m) );\n        set_free(&m);\n    }\n\n    {\n        set(char*) m = {0};\n        set_init(&m, cmp_str, hash_str);\n            assert( set_count(&m) == 0 );\n        set_insert(&m, \"123\");\n        set_insert(&m, \"456\");\n            assert( set_count(&m) == 2 );\n            assert( set_find(&m,\"123\") );\n            assert( set_find(&m,\"456\") );\n            assert(!set_find(&m,\"789\") );\n\n        set_foreach(&m,const char *,k) {\n            printf(\"%s\\n\", k);\n        }\n\n        set_erase(&m, \"123\");\n            assert( 0 == strcmp(\"456\", *set_find(&m,\"456\")) );\n            assert( set_count(&m) == 1 );\n        set_erase(&m, \"456\");\n            assert( set_count(&m) == 0 );\n        set_free(&m);\n\n        assert(!puts(\"Ok\"));\n    }\n}\n\nvoid set_tests2() {\n    set(char*) m;\n\n    set_init(&m, cmp_str, hash_str);\n\n    set_insert(&m, \"hello\");\n    set_insert(&m, \"world\");\n    set_insert(&m, \"nice\");\n    set_insert(&m, \"hash\");\n\n    assert(!set_find(&m, \"random\"));\n\n    assert(set_find(&m, \"hello\"));\n    assert(set_find(&m, \"world\"));\n    assert(set_find(&m, \"nice\"));\n    assert(set_find(&m, \"hash\"));\n\n    assert( 0 == strcmp(\"hello\", *set_find(&m, \"hello\")));\n    assert( 0 == strcmp(\"world\", *set_find(&m, \"world\")));\n    assert( 0 == strcmp(\"nice\", *set_find(&m, \"nice\")));\n    assert( 0 == strcmp(\"hash\", *set_find(&m, \"hash\")));\n\n    // reinsertion\n    assert(set_insert(&m, \"hello\"));\n    assert(0 == strcmp(\"hello\", *set_find(&m, \"hello\")));\n\n    set_free(&m);\n\n    assert( !puts(\"Ok\") );\n}\n\nvoid set_benchmark() {\n    #ifndef NUM\n    #define NUM 2000000\n    #endif\n\n    set(int) m;\n    set_init(&m, cmp_int, hash_int);\n\n    clock_t t0 = clock();\n\n    for( int i = 0; i < NUM; ++i ) {\n        set_insert(&m, i);\n    }\n    for( int i = 0; i < NUM; ++i ) {\n        int *v = set_find(&m, i);\n        assert( v && *v == i );\n    }\n\n    double t = (clock() - t0) / (double)CLOCKS_PER_SEC;\n\n    printf(\"[0]=%d\\n\", *set_find(&m, 0));\n    printf(\"[N-1]=%d\\n\", *set_find(&m, NUM-1));\n    printf(\"%d ops in %5.3fs = %fM ops/s\\n\", (NUM*2), t, (NUM*2) / (1e6 * t) );\n\n    set_free(&m);\n}\n\nint main() {\n    set_tests();\n    puts(\"---\");\n    set_tests2();\n    puts(\"---\");\n    set_benchmark();\n    assert(~puts(\"Ok\"));\n}\n\n#define main main__\n#endif // SET_DEMO\n#endif // SET_C\n"
  },
  {
    "path": "vault/ds_sort.c",
    "content": "// compare (<0:less,0:equal,>0:greater) ----------------------------------------\n// - rlyeh, public domain\n\n// typed\nint sort_int(int a, int b);\nint sort_u64(uint64_t a, uint64_t b);\nint sort_str(const char *a, const char *b);\nint sort_ptr(void *a, void *b);\n\n// untyped (generic, qsort style). single indirection.\nint sort_int_qs(const void *a, const void *b);\nint sort_uns_qs(const void *a, const void *b);\nint sort_i16_qs(const void *a, const void *b);\nint sort_u16_qs(const void *a, const void *b);\nint sort_i32_qs(const void *a, const void *b);\nint sort_u32_qs(const void *a, const void *b);\nint sort_f32_qs(const void *a, const void *b);\nint sort_i64_qs(const void *a, const void *b);\nint sort_u64_qs(const void *a, const void *b);\nint sort_f64_qs(const void *a, const void *b);\nint sort_ptr_qs(const void *a, const void *b);\nint sort_str_qs(const void *a, const void *b);\nint sort_stri_qs(const void *a, const void *b);\nint sort_stra_qs(const void *a, const void *b);\n\n// untyped (generic, qsort style). double indirection.\nint sort_int_qs2(const void *a, const void *b);\nint sort_uns_qs2(const void *a, const void *b);\nint sort_i16_qs2(const void *a, const void *b);\nint sort_u16_qs2(const void *a, const void *b);\nint sort_i32_qs2(const void *a, const void *b);\nint sort_u32_qs2(const void *a, const void *b);\nint sort_f32_qs2(const void *a, const void *b);\nint sort_i64_qs2(const void *a, const void *b);\nint sort_u64_qs2(const void *a, const void *b);\nint sort_f64_qs2(const void *a, const void *b);\nint sort_ptr_qs2(const void *a, const void *b);\nint sort_str_qs2(const void *a, const void *b);\nint sort_stri_qs2(const void *a, const void *b);\nint sort_stra_qs2(const void *a, const void *b);\n\n// -----------------------------------------------------------------------------\n\n#ifdef SORT_C\n#pragma once\n\n// typed. no indirection.\n\nint sort_int(int a, int b) {\n    return a - b;\n}\nint sort_u64(uint64_t a, uint64_t b) {\n    return a > b ? +1 : -!!(a - b);\n}\nint sort_ptr(void *a, void *b) {\n    return (uintptr_t)a > (uintptr_t)b ? +1 : -!!((uintptr_t)a - (uintptr_t)b);\n}\nint sort_str(const char *a, const char *b) {\n#if 0 // useful?\n    int sa = strlen((const char*)a);\n    int sb = strlen((const char*)b);\n    return sa>sb ? +1 : sa<sb ? -1 : strncmp((const char*)a, (const char*)b, sa);\n#else\n    return strcmp((const char *)a, (const char *)b);\n#endif\n}\n\n// untyped (generic, qsort style). double indirection. decay & pass.\n\nint sort_int_qs2(const void *a, const void *b) { return  sort_int_qs(*(const int**)a, *(const int**)b); }\nint sort_uns_qs2(const void *a, const void *b) { return  sort_uns_qs(*(const unsigned**)a, *(const unsigned**)b); }\nint sort_i16_qs2(const void *a, const void *b) { return  sort_i16_qs(*(const int16_t**)a, *(const int16_t**)b); }\nint sort_u16_qs2(const void *a, const void *b) { return  sort_u16_qs(*(const uint16_t**)a, *(const uint16_t**)b); }\nint sort_i32_qs2(const void *a, const void *b) { return  sort_i32_qs(*(const int32_t**)a, *(const int32_t**)b); }\nint sort_u32_qs2(const void *a, const void *b) { return  sort_u32_qs(*(const uint32_t**)a, *(const uint32_t**)b); }\nint sort_f32_qs2(const void *a, const void *b) { return  sort_f32_qs(*(const float**)a, *(const float**)b); }\nint sort_i64_qs2(const void *a, const void *b) { return  sort_i64_qs(*(const int64_t**)a, *(const int64_t**)b); }\nint sort_u64_qs2(const void *a, const void *b) { return  sort_u64_qs(*(const uint64_t**)a, *(const uint64_t**)b); }\nint sort_f64_qs2(const void *a, const void *b) { return  sort_f64_qs(*(const double**)a, *(const double**)b); }\nint sort_ptr_qs2(const void *a, const void *b) { return  sort_ptr_qs(*(const uintptr_t**)a, *(const uintptr_t**)b); }\nint sort_str_qs2(const void *a, const void *b) { return  sort_str_qs(*(const char***)a, *(const char***)b); }\nint sort_stri_qs2(const void *a,const void *b) { return sort_stri_qs(*(const char***)a, *(const char***)b); }\nint sort_stra_qs2(const void *a,const void *b) { return sort_stra_qs(*(const char***)a, *(const char***)b); }\n\n// untyped (generic, qsort style). single indirection.\n\nint sort_int_qs(const void *a, const void *b) { return ( *((      int*)a) - *((      int*)b) ); }\nint sort_uns_qs(const void *a, const void *b) { return ( *(( unsigned*)a) - *(( unsigned*)b) ); }\nint sort_i16_qs(const void *a, const void *b) { return ( *((  int16_t*)a) - *((  int16_t*)b) ); }\nint sort_u16_qs(const void *a, const void *b) { return ( *(( uint16_t*)a) - *(( uint16_t*)b) ); }\nint sort_i32_qs(const void *a, const void *b) { return ( *((  int32_t*)a) - *((  int32_t*)b) ); }\nint sort_u32_qs(const void *a, const void *b) { return ( *(( uint32_t*)a) - *(( uint32_t*)b) ); }\nint sort_f32_qs(const void *p, const void *q) { const     float*a = (const     float*)p; const     float*b = (const     float*)q; return *a > *b ? +1 : -!!(*a-*b); }\nint sort_i64_qs(const void *p, const void *q) { const   int64_t*a = (const   int64_t*)p; const   int64_t*b = (const   int64_t*)q; return *a > *b ? +1 : -!!(*a-*b); }\nint sort_u64_qs(const void *p, const void *q) { const  uint64_t*a = (const  uint64_t*)p; const  uint64_t*b = (const  uint64_t*)q; return *a > *b ? +1 : -!!(*a-*b); }\nint sort_f64_qs(const void *p, const void *q) { const    double*a = (const    double*)p; const    double*b = (const    double*)q; return *a > *b ? +1 : -!!(*a-*b); }\nint sort_ptr_qs(const void *p, const void *q) { const uintptr_t*a = (const uintptr_t*)p; const uintptr_t*b = (const uintptr_t*)q; return *a > *b ? +1 : -!!(*a-*b); }\n\nint sort_str_qs(const void *a, const void *b) { // str\n    const char *sa = *(const char **)a;\n    const char *sb = *(const char **)b;\n    return strcmp(sa, sb);\n}\nint sort_stri_qs(const void *a, const void *b) { // str\n    const char *sa = *(const char **)a;\n    const char *sb = *(const char **)b;\n    for( ; *sa && *sb ; ++sa, ++sb ) {\n        if( ((*sa)|32) != ((*sb)|32)) {\n            break;\n        }\n    }\n    return (*sa) - (*sb);\n}\nint sort_stra_qs(const void *a, const void *b) { // str\n    const char *sa = *(const char **)a;\n    const char *sb = *(const char **)b;\n    int sort__alphanum(const char *l, const char *r);\n    return sort__alphanum(sa, sb);\n}\n\n#include <ctype.h>\nint sort__alphanum(const char *l, const char *r) {\n    /* The Alphanum Algorithm is an improved sorting algorithm for strings\n    containing numbers.  Instead of sorting numbers in ASCII order like a\n    standard sort, this algorithm sorts numbers in numeric order.\n    The Alphanum Algorithm is discussed at http://www.DaveKoelle.com\n\n    This implementation is Copyright (c) 2008 Dirk Jagdmann <doj@cubic.org>.\n    It is a cleanroom implementation of the algorithm and not derived by\n    other's works. In contrast to the versions written by Dave Koelle this\n    source code is distributed with the libpng/zlib license.\n    This software is provided 'as-is', without any express or implied\n    warranty. In no event will the authors be held liable for any damages\n    arising from the use of this software.\n    Permission is granted to anyone to use this software for any purpose,\n    including commercial applications, and to alter it and redistribute it\n    freely, subject to the following restrictions:\n        1. The origin of this software must not be misrepresented; you\n           must not claim that you wrote the original software. If you use\n           this software in a product, an acknowledgment in the product\n           documentation would be appreciated but is not required.\n        2. Altered source versions must be plainly marked as such, and\n           must not be misrepresented as being the original software.\n        3. This notice may not be removed or altered from any source\n           distribution. */\n    int is_string = 1;\n    while(*l && *r) {\n        if(is_string) {\n            char l_char, r_char;\n            while((l_char=*l) && (r_char=*r)) {\n                // check if this are digit characters\n                const bool l_digit=isdigit(l_char), r_digit=isdigit(r_char);\n                // if both characters are digits, we continue in NUMBER mode\n                if(l_digit && r_digit) {\n                    is_string = 0;\n                    break;\n                }\n                // if only the left character is a digit, we have a result\n                if(l_digit) return -1;\n                // if only the right character is a digit, we have a result\n                if(r_digit) return +1;\n                // compute the difference of both characters\n                const int diff=l_char - r_char;\n                // if they differ we have a result\n                if(diff != 0) return diff;\n                // otherwise process the next characters\n                ++l;\n                ++r;\n            }\n        } else { // mode==NUMBER\n            // get the left number\n            unsigned long l_int=0;\n            while(*l && isdigit(*l)) { // TODO: this can overflow\n                l_int=l_int*10 + *l-'0';\n                ++l;\n            }\n\n            // get the right number\n            unsigned long r_int=0;\n            while(*r && isdigit(*r)) { // TODO: this can overflow\n                r_int=r_int*10 + *r-'0';\n                ++r;\n            }\n\n            // if the difference is not equal to zero, we have a comparison result\n            const long diff=l_int-r_int;\n            if(diff != 0)\n                return diff;\n\n            // otherwise we process the next substring in STRING mode\n            is_string = 1;\n        }\n    }\n    if(*r) return -1;\n    if(*l) return +1;\n    return 0;\n}\n\n#ifdef SORT_DEMO\n#include <assert.h>\n#include <stdio.h>\nint main() {\n    uint64_t a64 = 0, b64 = 0;\n    assert( 0 == sort_u64(a64, b64));\n    const char *astr = \"hello\", *bstr = \"Hello\";\n    assert( 0  < sort_str(astr, bstr));\n    assert( 0 == sort_stri_qs(&astr, &bstr));\n    assert( 0  < sort_stra_qs(&astr, &bstr));\n    assert(~puts(\"Ok\"));\n}\n#define main main__\n#endif // SORT_DEMO\n#endif // SORT_C\n"
  },
  {
    "path": "vault/ds_stream.c",
    "content": "// stream: read/write/sync, stats, sim\n// implementations: mem/list(str), file/dir, tcp/udp, stdin/stdout, sql/kissdb\n// - rlyeh, public domain\n\n#ifndef STREAM_MEM_ENLARGE_FACTOR\n#define STREAM_MEM_ENLARGE_FACTOR 1.5 // 2 // 1.5\n#endif\n\n// hacky solution to an old problem: hook stdio.h to new tech, so old code gets free upgrades.\n// this is only enabled if STDIO2 is defined\n#ifdef STDIO2\n\n#define _FILE_OFFSET_BITS 64\n#ifdef __cplusplus\n#include <cstdio>\n#endif\n#include <stdio.h>\n\n#ifndef STDIO2_H\n#define STDIO2_H\ntypedef FILE STREAM_FILE;\n#define FILE                 STREAM\n#define fopen(uri,...)       stream_open((uri),__VA_ARGS__)\n#define fread(ptr,c,sz,fp)   (stream_read((fp),(ptr),(c)*(sz)) == (c)*(sz) ? (sz) : 0)\n#define fwrite(ptr,c,sz,fp)  (stream_puts((fp),(ptr),(c)*(sz)) == (c)*(sz) ? (sz) : 0)\n#define fclose(fp)           stream_shut((fp))\n#define ftell(fp)            stream_tell((fp))\n#define fputs(s,fp)          stream_puts((fp),(s),strlen(s)) // @todo: optimize\n#define fprintf              #error:not_supported // stream_puts((fp),va(__VA_ARGS__),strlen(va(__VA_ARGS__))) // @todo: optimize\n#define fseek(fp,p,m)        stream_seek((fp),(p),(m))\n#define fflush(fp)           stream_sync((fp))\n#define fgets                #error:not_supported\n#define fgetc                #error:not_supported\n#define fputc                #error:not_supported\n#define fscanf               #error:not_supported\n#define feof                 #error:not_supported\n#define ferror               #error:not_supported\n#define fgetpos              #error:not_supported\n#define fsetpos              #error:not_supported\n#define freopen              #error:not_supported\n#define funopen              #error:not_supported\n#define fopen_s(pfp,n,m)     ((*pfp) = fopen((n),(m)), -!(*pfp))\n#define fseeko               fseek\n#define _fseeki64            fseek\n#define ftello               ftell\n#define _ftelli64            ftell\n#endif\n#endif\n\n\n#ifndef STREAM_H\n#define STREAM_H\n#include <stdarg.h>\n\n// stream is a virtual interface that reads and writes bytes, with seeking support.\n// could have used funopen() instead, but it is not available everywhere.\n// ---\n// [x] transports: null://, file://, mem://.\n// [ ] extra transports: udp://, tcp://, http://, ftp://, ipc://, rpc://\n// [x] pipes: chain of transforms to apply after reading/before writing.\n// [ ] transactions: txbegin(id) + content + txend(id)\n// [x] linked streams -[hub]< (multicast write)\n// [ ] linked streams: >[sink]- >[multi]<) (multicast read, multicast read/write)\n\ntypedef struct STREAM STREAM;\n\n// basic usage\n//int   stream_stat(const char *spec); // check for presence\nSTREAM* stream_open(const char *spec, ...);\nint     stream_read(STREAM *s, void *ptr, int sz);\nint     stream_puts(STREAM *s, const void *ptr, int sz);\nint     stream_seek(STREAM *s, int offs, int mode);\nint     stream_tell(STREAM *s);\nint     stream_sync(STREAM *s);\nint     stream_shut(STREAM *s);\nint     stream_link(STREAM *s, STREAM *other);\nint     stream_pipe(STREAM *s, int(*pipe)(void *ptr, int sz) );\n\nchar   *stream_info(STREAM *s);\n\n// create and register new stream protocol\nint     stream_make(\n        const char *spec,\n        int (*open)(STREAM *self, const char *spec, va_list vl),\n        int (*read)(STREAM *self, void *ptr, int sz),\n        int (*puts)(STREAM *self, const void *ptr, int sz),\n        int (*seek)(STREAM *self, int offs, int mode),\n        int (*tell)(STREAM *self),\n        int (*sync)(STREAM *self),\n        int (*shut)(STREAM *self)\n);\n\n#endif\n\n// -----------------------------------------------------------------------------\n\n#ifdef STREAM_C\n#pragma once\n\n// null:// interface ----------------------------------------------------------\n\nstatic int nil_open(STREAM *s, const char *spec, va_list vl) { return 0; }\nstatic int nil_read(STREAM *s, void *ptr, int sz) { return sz; }\nstatic int nil_write(STREAM *s, const void *ptr, int sz) { return sz; }\nstatic int nil_seek(STREAM *s, int offs, int mode) { return 0; }\nstatic int nil_tell(STREAM *s) { return 0; }\nstatic int nil_sync(STREAM *s) { return 0; }\nstatic int nil_close(STREAM *s) { return 0; }\n\n// file:// interface ----------------------------------------------------------\n\ntypedef struct file {\n#ifdef STDIO2\n#undef FILE\n#endif\n    FILE *fp;\n#ifdef STDIO2\n#define FILE STREAM\n#endif\n} file;\n\nstatic int file_open(STREAM *s, const char *spec, va_list vl) {\n    return (((file*)s)->fp = (fopen)(spec, va_arg(vl, const char *))) ? 0 : -1;\n}\n\nstatic int file_read_(STREAM *s, void *ptr, int sz) {\n    return (fread)(ptr, 1, sz, ((file*)s)->fp);\n}\n\nstatic int file_write_(STREAM *s, const void *ptr, int sz) {\n    return (fwrite)(ptr, 1, sz, ((file*)s)->fp);\n}\n\nstatic int file_seek(STREAM *s, int offs, int mode) {\n    return (fseek)(((file*)s)->fp, offs, mode);\n}\n\nstatic int file_tell(STREAM *s) {\n    return (int)(ftell)(((file*)s)->fp);\n}\n\nstatic int file_sync(STREAM *s) {\n    return (fflush)(((file*)s)->fp), 0;\n}\n\nstatic int file_close(STREAM *s) {\n    return (fclose)(((file*)s)->fp), 0;\n}\n#if 1 // not used\nstatic int file_access( const char *filename ) {\n#ifdef _WIN\n    return _access( filename, 0 ) != -1 ? 0 : -1;\n#else\n    return access( filename, F_OK ) != -1 ? 0 : -1;\n#endif\n}\n#endif\n\n// mem:// interface -----------------------------------------------------------\n\n// @works: wb, rb\n// @todo: w+b, r+b, a+b, ab\n\ntypedef struct membuffer {\n    char *begin, *cur, *end, *bottom;\n    int owned; // true if using own allocated mem; false if using external mem\n    char *filename;\n    int mode;\n} membuffer;\n\ntypedef struct ramdisk {\n    char *filename;\n    char *begin, *end;\n    struct ramdisk *next;\n} ramdisk;\nramdisk *top = 0;\nramdisk *ramnew(void) {\n    if( !top ) return top = CALLOC(1,sizeof(ramdisk));\n    while(top->next) top = top->next;\n    return top->next = CALLOC(1,sizeof(ramdisk));\n}\nramdisk *ramfind(const char *filename) {\n    for(ramdisk *t = top; t; t = t->next) {\n        if(!strcmp(t->filename, filename)) return t;\n    }\n    return 0;\n}\n\nstatic int mem_open(STREAM *s, const char *spec, va_list vl) {\n#if 0\n    int external = 1;\n    char* begin = (char*)va_arg(vl, void*);\n    char* end = (char*)va_arg(vl, void*);\n#else\n    int external = 0;\n    char* begin = MALLOC(1), *end = begin+1;\n    const char *mode = va_arg(vl, const char *);\n\n    if( mode[0] == 'r' ) {\n        ramdisk *found = ramfind(spec);\n        if( found ) {\n            FREE(begin);\n            begin = found->begin;\n            end = found->end;\n        }\n    }\n#endif\n\n    membuffer *mb = (membuffer*)s;\n    mb->owned = !external; // !begin;\n    mb->begin = begin;\n    mb->cur = mb->begin;\n    mb->end = end;\n    mb->bottom = mb->end;\n    mb->filename = STRDUP(spec);\n    mb->mode = mode[0];\n\n    return 0;\n}\n\nstatic int mem_read(STREAM *s, void *ptr, int sz) {\n    membuffer *mb = (membuffer*)s;\n    int avail = mb->end - mb->cur;\n    if( avail < sz ) {\n        sz = avail;\n    }\n    memcpy(ptr, mb->cur, sz);\n    mb->cur += sz;\n    return sz;\n}\n\nstatic unsigned round_next_pow2(unsigned v) {\n    // compute the next highest power of 2 of 32-bit v\n    v--;\n    v |= v >> 1;\n    v |= v >> 2;\n    v |= v >> 4;\n    v |= v >> 8;\n    v |= v >> 16;\n    v++;\n    return v;\n}\n\nstatic int mem_write(STREAM *s, const void *ptr, int sz) {\n    membuffer *mb = (membuffer*)s;\n    int avail = mb->bottom - mb->cur;\n    if( mb->owned && sz >= avail ) { /* used to be > before adding extra zero comment below */ \n        int pointer = mb->cur - mb->begin;\n        int oldlen = (mb->end - mb->begin);\n        int oldcap = (mb->bottom - mb->begin);\n        int newcap = (oldcap + sz) * STREAM_MEM_ENLARGE_FACTOR;\n        // newcap = round_next_pow2(newcap);\n        mb->begin = REALLOC(mb->begin, newcap);\n        mb->cur = mb->begin + pointer;\n        mb->end = mb->begin + oldcap;\n        mb->bottom = mb->begin + newcap;\n    }\n    /* <-- check below removed because it does not work with streams of unknown size (mb->avail == 0)\n    if( mb->avail < sz ) {\n        sz = mb->avail;\n    }\n    */\n    memcpy(mb->cur, ptr, sz);\n    mb->cur += sz;\n    if(mb->cur > mb->end) mb->end = mb->cur + 1;\n    return sz;\n}\n\nstatic int mem_seek(STREAM *s, int offs, int mode) {\n    membuffer *mb = (membuffer*)s;\n    char *dst;\n    /**/ if( mode == SEEK_SET ) dst = mb->begin + offs;\n    else if( mode == SEEK_CUR ) dst = mb->cur + offs;\n    else if( mode == SEEK_END ) dst = mb->end - 1 + offs;\n    else return -1;\n    if( dst >= mb->begin && dst < mb->end) {\n        mb->cur = dst;\n        return 0;\n    }\n    return -1;\n}\n\nstatic int mem_tell(STREAM *s) {\n    membuffer *mb = (membuffer*)s;\n    return mb->cur - mb->begin;\n}\n\nstatic int mem_sync(STREAM *s) {\n    membuffer *mb = (membuffer*)s;\n    return 0;\n}\n\nstatic int mem_close(STREAM *s) {\n    membuffer *mb = (membuffer*)s;\n#if 0\n    if( mb->owned ) REALLOC( mb->begin, 0 );\n#else\n    if( mb->mode == 'w' ) {\n        ramdisk *found = ramfind(mb->filename);\n        if( !found ) found = ramnew();\n        if( found ) {\n            FREE(found->begin);\n            FREE(found->filename);\n            found->filename = STRDUP(mb->filename);\n            found->begin = mb->begin;\n            found->end = mb->end;\n        }\n    }\n#endif\n    return 0;\n}\n\n// stream ---------------------------------------------------------------------\n\ntypedef struct STREAM {\n    // opaque data always first member in struct.\n    // implementations can cast directly to their types as long as their sizes are less than sizeof(dummy).\n    char dummy[ 256 - sizeof(const char *) - sizeof(int(*)()) * (7+8) - sizeof(STREAM*) - 8*4 ];\n    // members\n    const char *spec;\n    int (*open)(void *self, const char *spec, ...);\n    int (*read)(void *self, void *ptr, int sz);\n    int (*puts)(void *self, const void *ptr, int sz);\n    int (*seek)(void *self, int offs, int mode);\n    int (*tell)(void *self);\n    int (*sync)(void *self);\n    int (*shut)(void *self);\n    int (*pipe[8])(void *ptr, int sz);\n    STREAM *next;\n    uint64_t rd, wr, rdb, wrb; // rd/wr hits, rd/wr bytes\n} STREAM;\n\ntypedef int sizeof_stream[ sizeof(STREAM) == 256 ];\n\nstatic STREAM sprotocols[32] = {0};\nstatic int sprotocols_count = 0;\n\nint stream_make(\n    const char *spec,\n    int (*open)(STREAM *self, const char *spec, va_list),\n    int (*read)(STREAM *self, void *ptr, int sz),\n    int (*puts)(STREAM *self, const void *ptr, int sz),\n    int (*seek)(STREAM *self, int offs, int mode),\n    int (*tell)(STREAM *self),\n    int (*sync)(STREAM *self),\n    int (*shut)(STREAM *self)\n) {\n    STREAM protocol = { {0}, spec, open, read, puts, seek, tell, sync, shut };\n    sprotocols[sprotocols_count++] = protocol;\n\n    // default to file:// (slot #0) if no explicit protocol is provided\n    int special_case = !strcmp(protocol.spec, \"file://\");\n    if( special_case ) {\n        STREAM swapped = sprotocols[ 0 ];\n        sprotocols[ 0 ] = sprotocols[ sprotocols_count - 1 ];\n        sprotocols[ sprotocols_count - 1 ] = swapped;\n    }\n\n    return 0;\n}\n\nSTREAM *stream_open(const char *spec, ...) {\n    static int registered = 0;\n    if( !registered ) { // auto-register provided interfaces\n        registered = 1;\n        stream_make( \"file://\", file_open, file_read_, file_write_, file_seek, file_tell, file_sync, file_close );\n        stream_make( \"mem://\", mem_open, mem_read, mem_write, mem_seek, mem_tell, mem_sync, mem_close );\n        stream_make( \"null://\", nil_open, nil_read, nil_write, nil_seek, nil_tell, nil_sync, nil_close );\n    }\n    STREAM *self = (STREAM*)REALLOC(0, sizeof(STREAM));\n    *self = sprotocols[0]; // default file:// interface\n    if( strstr(spec, \"://\") ) {\n        for( int i = 0; i < sprotocols_count; ++i ) {\n            if( strstr(spec, sprotocols[i].spec) ) {\n                *self = sprotocols[i];\n                spec += strlen(sprotocols[i].spec);\n                break;\n            }\n        }\n    }\n\n    va_list vl;\n    va_start(vl, spec);\n    if( 0 != self->open( self, spec, vl ) ) {\n        REALLOC(self, 0);\n        self = 0;\n    }\n    va_end(vl);\n\n    return self;\n}\n\nint stream_pipe(STREAM *self, int(*pipe)(void*,int)) {\n    int it = 0; \n    for(;it <= 8 && self->pipe[it]; ++it);\n    return it == 8 ? -1 : (self->pipe[it] = pipe, 0);\n}\n\nstatic\nint read_loop(STREAM *self, void *buffer, int count) {\n    int offset = 0;\n    while( count > 0 ) {\n        int block = self->read(self, (char *)buffer + offset, count);\n\n        if( block <= 0 ) { // < 0 for blocking sockets!\n            return block;\n        }\n        if( block ) {\n            offset += block;\n            count -= block;\n\n            ++self->rd;\n            self->rdb += block;\n        }\n    }\n    return offset;\n}\n\nstatic\nint write_loop(STREAM *self, const void *buffer, int count) {\n    int offset = 0;\n    while( count > 0 ) {\n        int block = self->puts(self, (const char *)buffer + offset, count);\n\n        if (block <= 0) { // < 0 for blocking sockets!\n            return block;\n        }\n        if( block ) {\n            offset += block;\n            count -= block;\n\n            ++self->wr;\n            self->wrb += block;\n        }\n    }\n    return offset;\n}\n\nint stream_read(STREAM *self, void *ptr, int sz) {\n    int rc = 0;\n    while( self ) {\n        rc = read_loop(self, ptr, sz);\n        for(int it=0;it<8 && rc>=0;++it) rc = self->pipe[it] ? self->pipe[it]((void*)ptr, sz) : rc;\n        if( rc < 0 ) break;\n\n        self = self->next;\n    }\n    return rc;\n}\n\nint stream_puts(STREAM *self, const void *ptr, int sz) {\n    int rc = 0;\n    while( self ) {\n        for(int it=0;it<8 && rc>=0;++it) rc = self->pipe[it] ? self->pipe[it]((void*)ptr, sz) : rc;\n        rc = write_loop(self, ptr, sz);\n        if( rc < 0 ) break;\n\n        self = self->next;\n    }\n    return rc;\n}\n\nint stream_seek(STREAM *self, int offs, int mode) {\n    int errors = 0;\n    while( self ) {\n        STREAM *next = self->next;\n        errors |= !!self->seek(self, offs, mode);\n        self = next;\n    }\n    return -errors;\n}\n\nint stream_tell(STREAM *self) {\n    int minimum = INT_MAX;\n    while( self ) {\n        STREAM *next = self->next;\n        int at = self->tell(self);\n        if( at < minimum ) minimum = at;\n        self = next;\n    }\n    return minimum;\n}\n\nint stream_sync(STREAM *self) {\n    while( self ) {\n        STREAM *next = self->next;\n        self->sync(self);\n        self = next;\n    }\n    return 0;\n}\n\nint stream_shut(STREAM *self) {\n    while( self ) {\n        STREAM *next = self->next;\n        self->sync(self);\n        self->shut(self);\n        free(self);\n        self = next;\n    }\n    return 0;\n}\n\nint stream_link(STREAM *self, STREAM *other) {\n    if( !self->next ) return !!(self->next = other);\n    return stream_link(self->next, other);\n}\n\nchar* stream_info(STREAM *self) {\n    static __declspec(thread) char buf[128];\n    snprintf(buf, 128, \"[STREAM:%p]: puts/pull %llu/%llu bytes (%llu/%llu ops)\", self, self->wrb, self->rdb, self->wr, self->rd);\n    return buf;\n}\n\n#endif\n"
  },
  {
    "path": "vault/ds_string.c",
    "content": "// string library\n// - rlyeh, public domain\n\n#ifndef STRING_H\n#define STRING_H\n\n// temporary strings api (stack)\n#define strtmp(fmt, ...)  va(fmt, __VA_ARGS__)\n\n// allocated strings api (heap)\n#define strnew(fmt, ...)  STRDUP(va(fmt,__VA_ARGS__))\n#define strdel(s)         ((is_va(s) ? (void)0 : REALLOC((s), 0)), (s)=0)\n#define stradd(s,fmt,...) stradd((s), va(fmt, __VA_ARGS__))\n\n// string utils (beware! destructive operations mostly)\nchar*           strlower(char *s);\nchar*           strupper(char *s);\nchar*           strcamel(char *s);\nchar*           strtrim(char *s);\nchar*           strswap(char *s, const char *src, const char *dst);\nint             strmatch(const char *s, const char *wildcard);\nuint64_t        strhash(const char *s);\narray(uint32_t) strutf8(const char *utf8);\nconst char*     strrstr(const char *s1, const char *s2);\nchar*           strmap(char *inout, const char *src, const char *dst);\nint             strhead( const char *string, const char *substr );\nint             strtail( const char *s, const char *e );\nchar*           strflip(char *s);\nconst char*     strsub( const char *str, int pos );\nint             streq( const char *string, const char *substr );\nint             streqi( const char *string, const char *substr );\nconst char*     strskip(const char *s, const char *chars);\nconst char*     strfind(const char *s, const char *chars);\nchar*           (stradd)(char **s, const char *s2);\n\n// tokenizer utils\nchar**          strsplit(const char *string, const char *delimiters); // adds additional eos\nchar*           strjoin(int num, char **list, const char *separator); // if num<=0, check for eos\nint             strchop(const char *string, const char *substr, char **left, char **right);\n\n// tokenizer utils (array version; without trailing null string)\narray(char*)    strsplit2(const char *string, const char *delimiters);\nchar*           strjoin2(array(char*) list, const char *separator);\n\n// aliases\ntypedef char*   string;\n\n#endif\n\n// -----------------------------------------------------------------------------\n\n#ifdef STRING_C\n#pragma once\n\n#if defined _MSC_VER && !defined __thread\n#define __thread __declspec(thread)\n#endif\n\n#include <assert.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n// tokenizer -------------------------------------------------------------------\n\narray(char*) strsplit(const char *text_, const char *delimiters) {\n    static __thread char *mems[16] = {0};\n    static __thread array(char*) list[16] = {0};\n    static __thread int list_count = 0;\n\n    int len = strlen(text_);\n\n    int slot = (list_count = (list_count+1) % 16);\n    mems[slot] = REALLOC(mems[slot], len+1);\n\n    char *text = mems[slot];\n    memcpy(text, text_, len+1);\n\n    array(char *) *out = &list[slot];\n    array_clear(*out);\n\n    int found[256] = {1,0}, i = 0;\n    while( *delimiters ) found[(unsigned char)*delimiters++] = 1;\n    while( text[i] ) {\n        int begin = i; while(text[i] && !found[(unsigned char)text[i]]) ++i;\n        int end = i;   while(text[i] &&  found[(unsigned char)text[i]]) ++i;\n        if (end > begin) {\n            array_push(*out, (text + begin));\n            (text + begin)[ end - begin ] = 0;\n        }\n    }\n    array_push(*out, 0); //(end of array)\n    return *out;\n}\nchar* strjoin(int num_list, char **list, const char *separator) {\n#if 1\n    static __thread char* mems[16] = {0};\n    static __thread int num = 0;\n    int slot = (num = (num+1) % 16);\n\n    int len = 0, inc = 0, seplen = strlen(separator);\n    for( int i = 0; (num_list > 0 ? i < num_list : !!list[i]); ++i ) {\n        len += strlen(list[i]) + inc;\n        inc = seplen;\n    }\n\n    mems[slot] = REALLOC(mems[slot], len+1);\n    char *p = mems[slot]; *p = 0;\n    const char *sep = \"\";\n    for( int i = 0; (num_list > 0 ? i < num_list : !!list[i]); ++i ) {\n        p += sprintf(p, \"%s%s\", sep, list[i]);\n        sep = separator;\n    }\n\n    return mems[slot];\n#else\n    char *x = 0, *sep = \"\";\n    for( int i = 0; (num_list > 0 ? i < num_list : !!list[i]); ++i ) {\n        stradd(&x, \"%s%s\", sep, list[i]);\n        sep = separator;\n    }\n    char *ret = va(\"%s\", x);\n    FREE(x);\n    return ret;\n#endif\n}\n\n#include <string.h>\narray(char*) strsplit2(const char *str, const char *separator) { // @todo: replaces strsplit?\n    static __thread int slot = 0;\n    static __thread char *buf[16] = {0};\n    static __thread array(char*) list[16] = {0};\n\n    slot = (slot+1) % 16;\n    array_resize(list[slot], 0);\n    buf[slot] = REALLOC(buf[slot], strlen(str)+1);\n\n    for(char *dst = buf[slot]; str && *str; ) {\n        // find && skip separator\n       const char *sep = strpbrk(str, separator);\n       const char *src = str; int slen = (int)(sep - src);\n       str = sep + (sep ? strspn(sep, separator) : 0);\n\n       // append & update content\n       array_push(list[slot], dst);\n       memcpy((dst += slen) - slen, src, slen);\n       *dst++ = '\\0';\n    }\n\n    return list[slot];\n}\nchar *strjoin2(array(char*) list, const char *separator) {\n    return strjoin( array_count(list), list, separator );\n}\n\n// string utils ----------------------------------------------------------------\n\nconst char *strsub( const char *str, int pos ) {\n    int size = strlen(str);\n    pos = pos && size ? (pos > 0 ? pos % size : size-1 + ((pos+1) % size)) : 0;\n    return str + pos;\n}\nint streq( const char *string, const char *substr ) {\n    return strcmp( string, substr );\n}\nint streqi( const char *string, const char *substr ) {\n    while( *string && *substr ) {\n        int eqi = (*string++ | 32) - (*substr++ | 32);\n        if( eqi ) return eqi;\n    }\n    return *string - *substr;\n}\nchar *strflip(char *str) { // Based on code by Bob Stout (public domain).\n    if(str && *str)\n    for( char *p1 = str, *p2 = p1 + strlen(p1) - 1; p2 > p1; ++p1, --p2 ) {\n        *p1 ^= *p2;\n        *p2 ^= *p1;\n        *p1 ^= *p2;\n    }\n    return str;\n}\n// skip all occurences of 'chars' in s\nconst char *strskip(const char *s, const char *chars) {\n    return s + strspn(s, chars);\n}\n// find any of 'chars' in s. null if no matches are found.\nconst char *strfind(const char *s, const char *chars) {\n    return strpbrk(s, chars);\n}\n// returns true if text starts with substring\nint strhead( const char *str, const char *substr ) {\n    return strncmp(str, substr, strlen(substr)) == 0;\n}\n// returns true if text ends with substring\nint strtail( const char *s, const char *e ) {\n    int ls = strlen(s);\n    int le = strlen(e);\n    if( ls < le ) return 0;\n    return 0 == memcmp( s + ls - le, e, le );\n}\nstatic char *strmap_(char *inout, const char *src, const char *dst) {\n    char *find = strpbrk(inout, src);\n    if(!find) return inout;\n    char *which = strchr(src, find[0]);\n    int distance = (int)( which - src );\n    int len = strlen(dst);\n    if( distance < len ) {\n        *find = dst[distance];\n        return strmap_(find+1, src, dst); // continue mapping\n    } else {\n        char *ptr = find;\n        do ptr[0] = ptr[1]; while( *++ptr ); // memmove one\n        return strmap_(find, src, dst);\n    }\n}\nchar *strmap(char *inout, const char *src, const char *dst) {\n    // assert(strlen(src) >= strlen(dst));\n    if(strlen(src) == strlen(dst)) {\n        uint8_t map[256] =\n        \"\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\"\n        \"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\"\n        \"\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a\\x2b\\x2c\\x2d\\x2e\\x2f\"\n        \"\\x30\\x31\\x32\\x33\\x34\\x35\\x36\\x37\\x38\\x39\\x3a\\x3b\\x3c\\x3d\\x3e\\x3f\"\n        \"\\x40\\x41\\x42\\x43\\x44\\x45\\x46\\x47\\x48\\x49\\x4a\\x4b\\x4c\\x4d\\x4e\\x4f\"\n        \"\\x50\\x51\\x52\\x53\\x54\\x55\\x56\\x57\\x58\\x59\\x5a\\x5b\\x5c\\x5d\\x5e\\x5f\"\n        \"\\x60\\x61\\x62\\x63\\x64\\x65\\x66\\x67\\x68\\x69\\x6a\\x6b\\x6c\\x6d\\x6e\\x6f\"\n        \"\\x70\\x71\\x72\\x73\\x74\\x75\\x76\\x77\\x78\\x79\\x7a\\x7b\\x7c\\x7d\\x7e\\x7f\"\n        \"\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\"\n        \"\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\"\n        \"\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\"\n        \"\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\"\n        \"\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\"\n        \"\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\"\n        \"\\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\"\n        \"\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\";\n        for( int i = 0; src[i]; ++i) map[(uint8_t)src[i]] = dst[i];\n        for( int i = 0; inout[i]; ++i ) inout[i] = map[(uint8_t)inout[i]];\n        return inout;\n    }\n    return strmap_(inout, src, dst), inout;\n}\nconst char *strrstr(const char *s1, const char *s2) {\n    int s1len = strlen(s1);\n    char *find = strstr(s1, s2), *find1;\n    if( !find ) return s1 + s1len;\n    while( (find1 = strstr(find+s1len,s2)) != 0 ) find = find1;\n    return find;\n}\nchar *strlower( char *copy ) {\n    for( char *s = copy; *s; ++s ) *s = tolower(*s); // &= ~32\n    return copy;\n}\nchar *strupper( char *copy ) {\n    for( char *s = copy; *s; ++s ) *s = toupper(*s); // |= 32\n    return copy;\n}\nchar *strcamel( char *copy ) {\n    for( char *s = copy; *s; ++s ) *s = tolower(*s); // &= ~32\n    char **list = strsplit(copy, \" \");\n    for( int i = 0; list[i]; ++i ) list[i][0] = toupper(list[i][0]);\n    return strcpy(copy, strjoin(0, list, \"\"));\n}\nchar* strtrim(char *str) {\n    // trims leading, trailing and excess whitespaces.\n    char *ibuf, *obuf;\n    if( str ) {\n        for( ibuf = obuf = str; *ibuf; ) {\n            while( *ibuf && isspace(*ibuf)  )  (ibuf++);\n            if(    *ibuf && obuf != str     ) *(obuf++) = ' ';\n            while( *ibuf && !isspace(*ibuf) ) *(obuf++) = *(ibuf++);\n        }\n        *obuf = 0;\n    }\n    return str;\n}\nchar *strswap( char *copy, const char *target, const char *replacement ) {\n    // replaced only if new text is shorter than old one\n    int rlen = strlen(replacement), diff = strlen(target) - rlen;\n    if( diff >= 0 ) {\n        for( char *s = copy, *e = s + strlen(copy); /*s < e &&*/ 0 != (s = strstr(s, target)); ) {\n            if( rlen ) s = (char*)memcpy( s, replacement, rlen ) + rlen;\n            if( diff ) memmove( s, s + diff, (e - (s + diff)) + 1 );\n        }\n    }\n    return copy;\n}\nint strmatch(const char *s, const char *wildcard) {\n    // returns true if wildcard matches\n    if( *wildcard=='\\0' ) return !*s;\n    if( *wildcard=='*' )  return strmatch(s, wildcard+1) || (*s && strmatch(s+1, wildcard));\n    if( *wildcard=='?' )  return *s && (*s != '.') && strmatch(s+1, wildcard+1);\n    return (*s == *wildcard) && strmatch(s+1, wildcard+1);\n}\nuint64_t strhash( const char *s ) { // for convenience. wrapper over original hash_str() function\n    return hash_str(s);\n//  uint64_t hash = 0; // fnv1a: 14695981039346656037ULL;\n//  while( *s++ ) hash = ( s[-1] ^ hash ) * 131; // fnv1a: 0x100000001b3ULL; }\n//  return hash;\n}\narray(uint32_t) strutf8( const char *utf8 ) {\n    // Based on code by @ddiakopoulos (unlicensed).\n    // Based on code by @nothings (public domain).\n    array(uint32_t) out = 0; //array_reserve(out, strlen(utf8) + 1);\n    while( *utf8 ) {\n        const char **p = &utf8;\n        uint32_t unicode = 0;\n        /**/ if( (**p & 0x80) == 0x00 ) {\n            int a = *((*p)++);\n            unicode = a;\n        }\n        else if( (**p & 0xe0) == 0xc0 ) {\n            int a = *((*p)++) & 0x1f;\n            int b = *((*p)++) & 0x3f;\n            unicode = (a << 6) | b;\n        }\n        else if( (**p & 0xf0) == 0xe0 ) {\n            int a = *((*p)++) & 0x0f;\n            int b = *((*p)++) & 0x3f;\n            int c = *((*p)++) & 0x3f;\n            unicode = (a << 12) | (b << 6) | c;\n        }\n        else if( (**p & 0xf8) == 0xf0 ) {\n            int a = *((*p)++) & 0x07;\n            int b = *((*p)++) & 0x3f;\n            int c = *((*p)++) & 0x3f;\n            int d = *((*p)++) & 0x3f;\n            unicode = (a << 18) | (b << 12) | (c << 8) | d;\n        }\n        array_push(out, unicode);\n    }\n    return out;\n}\n\nint strchop(const char *src, const char *substr, char **left, char **right) {\n    char *find = strstr(src, substr);\n    if( !find ) return *left = va(\"\"), *right = va(\"\"), 0;\n    *left = va(\"%.*s\", (int)(find - src), src);\n    *right = va(\"%s\", find + strlen(substr));\n    return 1;\n}\n\nchar *(stradd)(char **x, const char *buf) {\n    char *z = x && *x ? *x : 0;\n    int bl = strlen(buf);\n    int zl = (z ? strlen(z) : 0);\n    z = REALLOC(z, zl + bl + 1 );\n    memcpy(z + zl, buf, bl + 1 );\n    if( x && *x ) *x = z;\n    return z;\n}\n\n// -----------------------------------------------------------------------------\n\n#ifdef STRING_DEMO\n#pragma once\nint main() {\n    // test creation & destruction\n    char *x = strtmp(\"hello %d\", 123); puts(x); strdel(x); assert(x == 0); // optional free, since x is a temporary string (strtmp)\n    char *y = strnew(\"hello %d\", 123); puts(y); strdel(y); assert(y == 0); // required free, since y was explicitly allocated (with strnew)\n\n    // test concat\n    char *z = strtmp(\"%d\",6); z = strtmp(\"%s%s%s\",z,z,z); assert( 0 == strcmp(z,\"666\") );\n\n    // test memory is never exhausted\n    for(int i = 0; i < 10000; ++i) assert(strtmp(\"hello %d\",123));\n\n    // test utils 1/3\n    char buf[128];\n    puts( strswap( strcpy(buf, \"abracadabra\"), \"bra\", \"BRA\") ); // same len\n    puts( strswap( strcpy(buf, \"abracadabra\"), \"bra\", \"BR\") );  // smaller len\n    puts( strswap( strcpy(buf, \"abracadabra\"), \"bra\", \"B\") );   // smaller len\n    puts( strswap( strcpy(buf, \"abracadabra\"), \"bra\", \"\") );    // erase\n    puts( strswap( strcpy(buf, \"abracadabra\"), \"boo\", \"foo\") ); // no matches\n\n    // test utils 2/3\n    puts( strcamel(\"Camel case TEST\") );\n\n    // test utils 3/3\n    array(char*) tokens = strsplit(\"JAN,;,FEB,MAR,,APR\", \",;\");\n    puts(strjoin( tokens, \"/\" ));\n\n    // strrstr\n    puts( strrstr(\"banana\",  \"an\") );\n    puts( strrstr(\"banana\",  \"ban\") );\n    puts( strrstr(\"banana\",  \"xxx\") );\n\n    // strmap\n    char banana[] = \"BANANA\";\n    assert(!strcmp(\"banana\", strmap(banana, \"BNACXYZ \", \"bnac\")));\n    char stairway[] = \"There's a lady who's sure ... \";\n    assert(!strcmp(\"There'saladywho'ssure...\", strmap(stairway, \" \", \"\")));\n    char remap[] = \"h3110 w0r1d\";\n    assert( 0 == strcmp(\"hello world\", strmap(remap, \"310\", \"elo\")));\n\n    // \n    char *left, *right;\n    strchop(\"abracadabra\", \"ca\", &left, &right);  assert(!strcmp(\"abra\",left)); assert(!strcmp(\"dabra\",right));\n    strchop(\"abracadabra\", \"xxx\", &left, &right); assert(!strcmp(\"\",left)); assert(!strcmp(\"\",right));\n\n    char hello2[] = \"hello cruel world\";\n    assert( 0 == strcmp(\"hello world\", strswap(hello2, \"cruel \", \"\")) );\n    assert( 0 == strcmp(\"dlrow olleh\", strflip(hello2)) );\n\n    //\n    assert( strhead(\"banana\", \"ban\") );\n    assert(!strhead(\"banana\", \"xxx\") );\n    assert( strtail(\"banana\", \"ana\") );\n    assert(!strtail(\"banana\", \"xxx\") );\n    assert( strhead(\"hello\", \"hell\") );\n    assert(!strhead(\"hell\", \"hello\") );\n    assert( strtail(\"hello\", \"llo\") );\n\n    // \n    assert(!streq(\"hello\", \"hello\") );\n    assert( streq(\"HELLO\", \"hello\") );\n    assert(!streqi(\"hello\", \"hello\") );\n    assert(!streqi(\"HELLO\", \"hello\") );\n\n    assert(!strcmp(strsub(\"hello world\",6),strsub(\"hello world\", -5))); // world\n    assert(!strcmp(\"hello world\", strskip(\"   \\t\\rhello world\", \" \\t\\r\")));\n    assert(!strcmp(\"(world)\", strfind(\"hello(world)\", \"()\")));\n\n    // test asserts are enabled\n    assert(~puts(\"Ok\"));\n}\n#define main main__\n#endif // STRING_DEMO\n#endif // STRING_C\n"
  },
  {
    "path": "vault/net.c",
    "content": "// - rlyeh, public domain\n\n#ifdef NET_C\n//#pragma once\n#define ECDH_C\n#define TCP_C\n#define FRAGMENT_C\n#define TUNNEL_C\n#define WEBSERVER_C\n#endif\n\n#include \"os.c\"\n#include \"ds.c\"\n#include \"net_tcp.c\"\n#include \"net_ecdh.h\"\n#include \"net_fragment.c\"\n#include \"net_tunnel.c\"\n#include \"net_webserver.c\"\n"
  },
  {
    "path": "vault/net_ecdh.h",
    "content": "//#define ECC_CURVE NIST_K571 // 256bit, secure key is empty\n//#define ECC_CURVE NIST_B571 // 256bit, secure keys do not match\n//#define ECC_CURVE NIST_K409 // 192bit, secure key is empty\n  #define ECC_CURVE NIST_B409 // 192bit, ok\n\n\n// Diffie-Hellman key exchange (without HMAC) aka ECDH_anon in RFC4492\n// https://github.com/kokke/tiny-ECDH-c/ (UNLICENSE)\n/*\nThis is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <http://unlicense.org>\n*/\n\n/* \n\n  Crypto using elliptic curves defined over the finite binary field GF(2^m) where m is prime.\n\n  The curves used are the anomalous binary curves (ABC-curves) or also called Koblitz curves.\n\n  This class of curves was chosen because it yields efficient implementation of operations.\n\n\n\n  Curves available - their different NIST/SECG names and eqivalent symmetric security level:\n\n      NIST      SEC Group     strength\n    ------------------------------------\n      K-163     sect163k1      80 bit\n      B-163     sect163r2      80 bit\n      K-233     sect233k1     112 bit\n      B-233     sect233r1     112 bit\n      K-283     sect283k1     128 bit\n      B-283     sect283r1     128 bit\n      K-409     sect409k1     192 bit\n      B-409     sect409r1     192 bit\n      K-571     sect571k1     256 bit\n      B-571     sect571r1     256 bit\n\n\n\n  Curve parameters from:\n\n    http://www.secg.org/sec2-v2.pdf\n    http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf\n\n\n  Reference:\n\n    https://www.ietf.org/rfc/rfc4492.txt \n*/\n\n#ifndef _ECDH_H__\n#define _ECDH_H__\n\n\n/* for size-annotated integer types: uint8_t, uint32_t etc. */\n#include <stdint.h> \n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#define NIST_B163  1\n#define NIST_K163  2\n#define NIST_B233  3\n#define NIST_K233  4\n#define NIST_B283  5\n#define NIST_K283  6\n#define NIST_B409  7\n#define NIST_K409  8 /* currently defunct :( */\n#define NIST_B571  9\n#define NIST_K571 10 /* also not working...  */\n\n/* What is the default curve to use? */\n#ifndef ECC_CURVE\n #define ECC_CURVE NIST_B163\n#endif\n\n#if defined(ECC_CURVE) && (ECC_CURVE != 0)\n #if   (ECC_CURVE == NIST_K163) || (ECC_CURVE == NIST_B163)\n  #define CURVE_DEGREE       163\n  #define ECC_PRV_KEY_SIZE   24\n #elif (ECC_CURVE == NIST_K233) || (ECC_CURVE == NIST_B233)\n  #define CURVE_DEGREE       233\n  #define ECC_PRV_KEY_SIZE   32\n #elif (ECC_CURVE == NIST_K283) || (ECC_CURVE == NIST_B283)\n  #define CURVE_DEGREE       283\n  #define ECC_PRV_KEY_SIZE   36\n #elif (ECC_CURVE == NIST_K409) || (ECC_CURVE == NIST_B409)\n  #define CURVE_DEGREE       409\n  #define ECC_PRV_KEY_SIZE   52\n #elif (ECC_CURVE == NIST_K571) || (ECC_CURVE == NIST_B571)\n  #define CURVE_DEGREE       571\n  #define ECC_PRV_KEY_SIZE   72\n #endif\n#else\n #error Must define a curve to use\n#endif\n\n#define ECC_PUB_KEY_SIZE     (2 * ECC_PRV_KEY_SIZE)\n\n\n/******************************************************************************/\n\n\n/* NOTE: assumes private is filled with random data before calling */\nint ecdh_generate_keys(uint8_t* public_key, const uint8_t* private_key);\n\n/* input: own private key + other party's public key, output: shared secret */\nint ecdh_shared_secret(const uint8_t* private_key, const uint8_t* others_pub, uint8_t* output);\n\n\n/* Broken :( .... */\nint ecdsa_sign(const uint8_t* private_key, uint8_t* hash, uint8_t* random_k, uint8_t* signature);\nint ecdsa_verify(const uint8_t* public_key, uint8_t* hash, const uint8_t* signature);\n\n\n/******************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n\n#endif /* #ifndef _ECDH_H__ */\n\n\n#ifdef ECDH_C\n#pragma once\n\n/* \n\n  Crypto using elliptic curves defined over the finite binary field GF(2^m) where m is prime.\n\n  The curves used are the anomalous binary curves (ABC-curves) or also called Koblitz curves.\n\n  This class of curves was chosen because it yields efficient implementation of operations.\n\n\n\n  Curves available - their different NIST/SECG names and eqivalent symmetric security level:\n\n      NIST      SEC Group     strength\n    ------------------------------------\n      K-163     sect163k1      80 bit\n      B-163     sect163r2      80 bit\n      K-233     sect233k1     112 bit\n      B-233     sect233r1     112 bit\n      K-283     sect283k1     128 bit\n      B-283     sect283r1     128 bit\n      K-409     sect409k1     192 bit\n      B-409     sect409r1     192 bit\n      K-571     sect571k1     256 bit\n      B-571     sect571r1     256 bit\n\n\n\n  Curve parameters from:\n\n    http://www.secg.org/sec2-v2.pdf\n    http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf\n\n\n  Reference:\n\n    https://www.ietf.org/rfc/rfc4492.txt \n*/\n\n#include <stdint.h>\n//#include \"ecdh.h\"\n\n\n/* margin for overhead needed in intermediate calculations */\n#define BITVEC_MARGIN     3\n#define BITVEC_NBITS      (CURVE_DEGREE + BITVEC_MARGIN)\n#define BITVEC_NWORDS     ((BITVEC_NBITS + 31) / 32)\n#define BITVEC_NBYTES     (sizeof(uint32_t) * BITVEC_NWORDS)\n\n\n/* Disable assertions? */\n#ifndef DISABLE_ASSERT\n #define DISABLE_ASSERT 0\n#endif\n\n#if defined(DISABLE_ASSERT) && (DISABLE_ASSERT == 1)\n #define assert(...)\n#else\n #include <assert.h>\n#endif\n\n/* Default to a (somewhat) constant-time mode?\n   NOTE: The library is _not_ capable of operating in constant-time and leaks information via timing.\n         Even if all operations are written const-time-style, it requires the hardware is able to multiply in constant time. \n         Multiplication on ARM Cortex-M processors takes a variable number of cycles depending on the operands...\n*/\n#ifndef CONST_TIME\n  #define CONST_TIME 0\n#endif\n\n/* Default to using ECC_CDH (cofactor multiplication-variation) ? */\n#ifndef ECDH_COFACTOR_VARIANT\n  #define ECDH_COFACTOR_VARIANT 0\n#endif\n\n/******************************************************************************/\n\n\n/* the following type will represent bit vectors of length (CURVE_DEGREE+MARGIN) */\ntypedef uint32_t bitvec_t[BITVEC_NWORDS];\ntypedef bitvec_t gf2elem_t;           /* this type will represent field elements */\ntypedef bitvec_t scalar_t;\n \n\n/******************************************************************************/\n\n/* Here the curve parameters are defined. */\n\n#if defined (ECC_CURVE) && (ECC_CURVE != 0)\n #if (ECC_CURVE == NIST_K163)\n  #define coeff_a  1\n  #define cofactor 2\n/* NIST K-163 */\nconst gf2elem_t polynomial = { 0x000000c9, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }; \nconst gf2elem_t coeff_b    = { 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; \nconst gf2elem_t base_x     = { 0x5c94eee8, 0xde4e6d5e, 0xaa07d793, 0x7bbc11ac, 0xfe13c053, 0x00000002 }; \nconst gf2elem_t base_y     = { 0xccdaa3d9, 0x0536d538, 0x321f2e80, 0x5d38ff58, 0x89070fb0, 0x00000002 }; \nconst scalar_t  base_order = { 0x99f8a5ef, 0xa2e0cc0d, 0x00020108, 0x00000000, 0x00000000, 0x00000004 }; \n #endif\n\n #if (ECC_CURVE == NIST_B163)\n  #define coeff_a  1\n  #define cofactor 2\n/* NIST B-163 */\nconst gf2elem_t polynomial = { 0x000000c9, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }; \nconst gf2elem_t coeff_b    = { 0x4a3205fd, 0x512f7874, 0x1481eb10, 0xb8c953ca, 0x0a601907, 0x00000002 }; \nconst gf2elem_t base_x     = { 0xe8343e36, 0xd4994637, 0xa0991168, 0x86a2d57e, 0xf0eba162, 0x00000003 }; \nconst gf2elem_t base_y     = { 0x797324f1, 0xb11c5c0c, 0xa2cdd545, 0x71a0094f, 0xd51fbc6c, 0x00000000 }; \nconst scalar_t  base_order = { 0xa4234c33, 0x77e70c12, 0x000292fe, 0x00000000, 0x00000000, 0x00000004 }; \n #endif\n\n #if (ECC_CURVE == NIST_K233)\n  #define coeff_a  0\n  #define cofactor 4\n/* NIST K-233 */\nconst gf2elem_t polynomial = { 0x00000001, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000200 };\nconst gf2elem_t coeff_b    = { 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };\nconst gf2elem_t base_x     = { 0xefad6126, 0x0a4c9d6e, 0x19c26bf5, 0x149563a4, 0x29f22ff4, 0x7e731af1, 0x32ba853a, 0x00000172 };\nconst gf2elem_t base_y     = { 0x56fae6a3, 0x56e0c110, 0xf18aeb9b, 0x27a8cd9b, 0x555a67c4, 0x19b7f70f, 0x537dece8, 0x000001db };\nconst scalar_t  base_order = { 0xf173abdf, 0x6efb1ad5, 0xb915bcd4, 0x00069d5b, 0x00000000, 0x00000000, 0x00000000, 0x00000080 };\n #endif\n\n #if (ECC_CURVE == NIST_B233)\n  #define coeff_a  1\n  #define cofactor 2\n/* NIST B-233 */\nconst gf2elem_t polynomial = { 0x00000001, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000200 }; \nconst gf2elem_t coeff_b    = { 0x7d8f90ad, 0x81fe115f, 0x20e9ce42, 0x213b333b, 0x0923bb58, 0x332c7f8c, 0x647ede6c, 0x00000066 }; \nconst gf2elem_t base_x     = { 0x71fd558b, 0xf8f8eb73, 0x391f8b36, 0x5fef65bc, 0x39f1bb75, 0x8313bb21, 0xc9dfcbac, 0x000000fa }; \nconst gf2elem_t base_y     = { 0x01f81052, 0x36716f7e, 0xf867a7ca, 0xbf8a0bef, 0xe58528be, 0x03350678, 0x6a08a419, 0x00000100 }; \nconst scalar_t  base_order = { 0x03cfe0d7, 0x22031d26, 0xe72f8a69, 0x0013e974, 0x00000000, 0x00000000, 0x00000000, 0x00000100 };\n #endif\n\n #if (ECC_CURVE == NIST_K283)\n  #define coeff_a  0\n  #define cofactor 4\n/* NIST K-283 */\nconst gf2elem_t polynomial = { 0x000010a1, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08000000 };\nconst gf2elem_t coeff_b    = { 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; \nconst gf2elem_t base_x     = { 0x58492836, 0xb0c2ac24, 0x16876913, 0x23c1567a, 0x53cd265f, 0x62f188e5, 0x3f1a3b81, 0x78ca4488, 0x0503213f }; \nconst gf2elem_t base_y     = { 0x77dd2259, 0x4e341161, 0xe4596236, 0xe8184698, 0xe87e45c0, 0x07e5426f, 0x8d90f95d, 0x0f1c9e31, 0x01ccda38 }; \nconst scalar_t  base_order = { 0x1e163c61, 0x94451e06, 0x265dff7f, 0x2ed07577, 0xffffe9ae, 0xffffffff, 0xffffffff, 0xffffffff, 0x01ffffff }; \n #endif\n\n #if (ECC_CURVE == NIST_B283)\n  #define coeff_a  1\n  #define cofactor 2\n/* NIST B-283 */\nconst gf2elem_t polynomial = { 0x000010a1, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08000000 }; \nconst gf2elem_t coeff_b    = { 0x3b79a2f5, 0xf6263e31, 0xa581485a, 0x45309fa2, 0xca97fd76, 0x19a0303f, 0xa5a4af8a, 0xc8b8596d, 0x027b680a }; \nconst gf2elem_t base_x     = { 0x86b12053, 0xf8cdbecd, 0x80e2e198, 0x557eac9c, 0x2eed25b8, 0x70b0dfec, 0xe1934f8c, 0x8db7dd90, 0x05f93925 }; \nconst gf2elem_t base_y     = { 0xbe8112f4, 0x13f0df45, 0x826779c8, 0x350eddb0, 0x516ff702, 0xb20d02b4, 0xb98fe6d4, 0xfe24141c, 0x03676854 }; \nconst scalar_t  base_order = { 0xefadb307, 0x5b042a7c, 0x938a9016, 0x399660fc, 0xffffef90, 0xffffffff, 0xffffffff, 0xffffffff, 0x03ffffff }; \n #endif\n\n #if (ECC_CURVE == NIST_K409)\n  #define coeff_a  0\n  #define cofactor 4\n/* NIST K-409 */\nconst gf2elem_t polynomial = { 0x00000001, 0x00000000, 0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000 }; \nconst gf2elem_t coeff_b    = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; \nconst gf2elem_t base_x     = { 0xe9023746, 0xb35540cf, 0xee222eb1, 0xb5aaaa62, 0xc460189e, 0xf9f67cc2, 0x27accfb8, 0xe307c84c, 0x0efd0987, 0x0f718421, 0xad3ab189, 0x658f49c1, 0x0060f05f }; \nconst gf2elem_t base_y     = { 0xd8e0286b, 0x5863ec48, 0xaa9ca27a, 0xe9c55215, 0xda5f6c42, 0xe9ea10e3, 0xe6325165, 0x918ea427, 0x3460782f, 0xbf04299c, 0xacba1dac, 0x0b7c4e42, 0x01e36905 }; \nconst scalar_t  base_order = { 0xe01e5fcf, 0x4b5c83b8, 0xe3e7ca5b, 0x557d5ed3, 0x20400ec4, 0x83b2d4ea, 0xfffffe5f, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x007fffff }; \n #endif\n\n #if (ECC_CURVE == NIST_B409)\n  #define coeff_a  1\n  #define cofactor 2\n/* NIST B-409 */\nconst gf2elem_t polynomial = { 0x00000001, 0x00000000, 0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000 }; \nconst gf2elem_t coeff_b    = { 0x7b13545f, 0x4f50ae31, 0xd57a55aa, 0x72822f6c, 0xa9a197b2, 0xd6ac27c8, 0x4761fa99, 0xf1f3dd67, 0x7fd6422e, 0x3b7b476b, 0x5c4b9a75, 0xc8ee9feb, 0x0021a5c2 }; \nconst gf2elem_t base_x     = { 0xbb7996a7, 0x60794e54, 0x5603aeab, 0x8a118051, 0xdc255a86, 0x34e59703, 0xb01ffe5b, 0xf1771d4d, 0x441cde4a, 0x64756260, 0x496b0c60, 0xd088ddb3, 0x015d4860 }; \nconst gf2elem_t base_y     = { 0x0273c706, 0x81c364ba, 0xd2181b36, 0xdf4b4f40, 0x38514f1f, 0x5488d08f, 0x0158aa4f, 0xa7bd198d, 0x7636b9c5, 0x24ed106a, 0x2bbfa783, 0xab6be5f3, 0x0061b1cf }; \nconst scalar_t  base_order = { 0xd9a21173, 0x8164cd37, 0x9e052f83, 0x5fa47c3c, 0xf33307be, 0xaad6a612, 0x000001e2, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000000 }; \n #endif\n\n #if (ECC_CURVE == NIST_K571)\n  #define coeff_a  0\n  #define cofactor 4\n/* NIST K-571 */\nconst gf2elem_t polynomial = { 0x00000425, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08000000 }; \nconst gf2elem_t coeff_b    = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; \nconst gf2elem_t base_x     = { 0xa01c8972, 0xe2945283, 0x4dca88c7, 0x988b4717, 0x494776fb, 0xbbd1ba39, 0xb4ceb08c, 0x47da304d, 0x93b205e6, 0x43709584, 0x01841ca4, 0x60248048, 0x0012d5d4, 0xac9ca297, 0xf8103fe4, 0x82189631, 0x59923fbc, 0x026eb7a8 }; \nconst gf2elem_t base_y     = { 0x3ef1c7a3, 0x01cd4c14, 0x591984f6, 0x320430c8, 0x7ba7af1b, 0xb620b01a, 0xf772aedc, 0x4fbebbb9, 0xac44aea7, 0x9d4979c0, 0x006d8a2c, 0xffc61efc, 0x9f307a54, 0x4dd58cec, 0x3bca9531, 0x4f4aeade, 0x7f4fbf37, 0x0349dc80 }; \nconst scalar_t  base_order = { 0x637c1001, 0x5cfe778f, 0x1e91deb4, 0xe5d63938, 0xb630d84b, 0x917f4138, 0xb391a8db, 0xf19a63e4, 0x131850e1, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000 }; \n #endif\n\n #if (ECC_CURVE == NIST_B571)\n  #define coeff_a  1\n  #define cofactor 2\n/* NIST B-571 */\nconst gf2elem_t polynomial = { 0x00000425, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08000000 }; \nconst gf2elem_t coeff_b    = { 0x2955727a, 0x7ffeff7f, 0x39baca0c, 0x520e4de7, 0x78ff12aa, 0x4afd185a, 0x56a66e29, 0x2be7ad67, 0x8efa5933, 0x84ffabbd, 0x4a9a18ad, 0xcd6ba8ce, 0xcb8ceff1, 0x5c6a97ff, 0xb7f3d62f, 0xde297117, 0x2221f295, 0x02f40e7e }; \nconst gf2elem_t base_x     = { 0x8eec2d19, 0xe1e7769c, 0xc850d927, 0x4abfa3b4, 0x8614f139, 0x99ae6003, 0x5b67fb14, 0xcdd711a3, 0xf4c0d293, 0xbde53950, 0xdb7b2abd, 0xa5f40fc8, 0x955fa80a, 0x0a93d1d2, 0x0d3cd775, 0x6c16c0d4, 0x34b85629, 0x0303001d }; \nconst gf2elem_t base_y     = { 0x1b8ac15b, 0x1a4827af, 0x6e23dd3c, 0x16e2f151, 0x0485c19b, 0xb3531d2f, 0x461bb2a8, 0x6291af8f, 0xbab08a57, 0x84423e43, 0x3921e8a6, 0x1980f853, 0x009cbbca, 0x8c6c27a6, 0xb73d69d7, 0x6dccfffe, 0x42da639b, 0x037bf273 }; \nconst scalar_t  base_order = { 0x2fe84e47, 0x8382e9bb, 0x5174d66e, 0x161de93d, 0xc7dd9ca1, 0x6823851e, 0x08059b18, 0xff559873, 0xe661ce18, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x03ffffff }; \n #endif\n#endif\n\n\n\n/*************************************************************************************************/\n\n/* Private / static functions: */\n\n\n/* some basic bit-manipulation routines that act on bit-vectors follow */\nstatic int bitvec_get_bit(const bitvec_t x, const uint32_t idx)\n{\n  return ((x[idx / 32U] >> (idx & 31U) & 1U));\n}\n\nstatic void bitvec_clr_bit(bitvec_t x, const uint32_t idx)\n{\n  x[idx / 32U] &= ~(1U << (idx & 31U));\n}\n\nstatic void bitvec_copy(bitvec_t x, const bitvec_t y)\n{\n  int i;\n  for (i = 0; i < BITVEC_NWORDS; ++i)\n  {\n    x[i] = y[i];\n  }\n}\n\nstatic void bitvec_swap(bitvec_t x, bitvec_t y)\n{\n  bitvec_t tmp;\n  bitvec_copy(tmp, x);\n  bitvec_copy(x, y);\n  bitvec_copy(y, tmp);\n}\n\n#if defined(CONST_TIME) && (CONST_TIME == 0)\n/* fast version of equality test */\nstatic int bitvec_equal(const bitvec_t x, const bitvec_t y)\n{\n  int i;\n  for (i = 0; i < BITVEC_NWORDS; ++i)\n  {\n    if (x[i] != y[i])\n    {\n      return 0;\n    }\n  }\n  return 1;\n}\n#else\n/* constant time version of equality test */\nstatic int bitvec_equal(const bitvec_t x, const bitvec_t y)\n{\n  int ret = 1;\n  int i;\n  for (i = 0; i < BITVEC_NWORDS; ++i)\n  {\n    ret &= (x[i] == y[i]);\n  }\n  return ret;\n}\n#endif\n\nstatic void bitvec_set_zero(bitvec_t x)\n{\n  int i;\n  for (i = 0; i < BITVEC_NWORDS; ++i)\n  {\n    x[i] = 0;\n  }\n}\n\n#if defined(CONST_TIME) && (CONST_TIME == 0)\n/* fast implementation */\nstatic int bitvec_is_zero(const bitvec_t x)\n{\n  uint32_t i = 0;\n  while (i < BITVEC_NWORDS)\n  {\n    if (x[i] != 0)\n    {\n      break;\n    }\n    i += 1;\n  }\n  return (i == BITVEC_NWORDS);\n}\n#else\n/* constant-time implementation */\nstatic int bitvec_is_zero(const bitvec_t x)\n{\n  int ret = 1;\n  int i = 0;\n  for (i = 0; i < BITVEC_NWORDS; ++i)\n  {\n    ret &= (x[i] == 0);\n  }\n  return ret;\n}\n#endif\n\n/* return the number of the highest one-bit + 1 */\nstatic int bitvec_degree(const bitvec_t x)\n{\n  int i = BITVEC_NWORDS * 32;\n\n  /* Start at the back of the vector (MSB) */\n  x += BITVEC_NWORDS;\n\n  /* Skip empty / zero words */\n  while (    (i > 0)\n          && (*(--x)) == 0)\n  {\n    i -= 32;\n  }\n  /* Run through rest if count is not multiple of bitsize of DTYPE */\n  if (i != 0)\n  {\n    uint32_t u32mask = ((uint32_t)1 << 31);\n    while (((*x) & u32mask) == 0)\n    {\n      u32mask >>= 1;\n      i -= 1;\n    }\n  }\n  return i;\n}\n\n/* left-shift by 'count' digits */\nstatic void bitvec_lshift(bitvec_t x, const bitvec_t y, int nbits)\n{\n  int nwords = (nbits / 32);\n\n  /* Shift whole words first if nwords > 0 */\n  int i,j;\n  for (i = 0; i < nwords; ++i)\n  {\n    /* Zero-initialize from least-significant word until offset reached */\n    x[i] = 0;\n  }\n  j = 0;\n  /* Copy to x output */\n  while (i < BITVEC_NWORDS)\n  {\n    x[i] = y[j];\n    i += 1;\n    j += 1;\n  }\n\n  /* Shift the rest if count was not multiple of bitsize of DTYPE */\n  nbits &= 31;\n  if (nbits != 0)\n  {\n    /* Left shift rest */\n    int i;\n    for (i = (BITVEC_NWORDS - 1); i > 0; --i)\n    {\n      x[i]  = (x[i] << nbits) | (x[i - 1] >> (32 - nbits));\n    }\n    x[0] <<= nbits;\n  }\n}\n\n\n/*************************************************************************************************/\n/*\n  Code that does arithmetic on bit-vectors in the Galois Field GF(2^CURVE_DEGREE).\n*/\n/*************************************************************************************************/\n\n\nstatic void gf2field_set_one(gf2elem_t x)\n{\n  /* Set first word to one */\n  x[0] = 1;\n  /* .. and the rest to zero */\n  int i;\n  for (i = 1; i < BITVEC_NWORDS; ++i)\n  {\n    x[i] = 0;\n  }\n}\n\n#if defined(CONST_TIME) && (CONST_TIME == 0)\n/* fastest check if x == 1 */\nstatic int gf2field_is_one(const gf2elem_t x) \n{\n  /* Check if first word == 1 */\n  if (x[0] != 1)\n  {\n    return 0;\n  }\n  /* ...and if rest of words == 0 */\n  int i;\n  for (i = 1; i < BITVEC_NWORDS; ++i)\n  {\n    if (x[i] != 0)\n    {\n      break;\n    }\n  }\n  return (i == BITVEC_NWORDS);\n}\n#else\n/* constant-time check */\nstatic int gf2field_is_one(const gf2elem_t x)\n{\n  int ret = 0;\n  /* Check if first word == 1 */\n  if (x[0] == 1)\n  {\n    ret = 1;\n  }\n  /* ...and if rest of words == 0 */\n  int i;\n  for (i = 1; i < BITVEC_NWORDS; ++i)\n  {\n    ret &= (x[i] == 0);\n  }\n  return ret; //(i == BITVEC_NWORDS);\n}\n#endif\n\n\n/* galois field(2^m) addition is modulo 2, so XOR is used instead - 'z := a + b' */\nstatic void gf2field_add(gf2elem_t z, const gf2elem_t x, const gf2elem_t y)\n{\n  int i;\n  for (i = 0; i < BITVEC_NWORDS; ++i)\n  {\n    z[i] = (x[i] ^ y[i]);\n  }\n}\n\n/* increment element */\nstatic void gf2field_inc(gf2elem_t x)\n{\n  x[0] ^= 1;\n}\n\n\n/* field multiplication 'z := (x * y)' */\nstatic void gf2field_mul(gf2elem_t z, const gf2elem_t x, const gf2elem_t y)\n{\n  int i;\n  gf2elem_t tmp;\n#if defined(CONST_TIME) && (CONST_TIME == 1)\n  gf2elem_t blind;\n  bitvec_set_zero(blind);\n#endif\n  assert(z != y);\n\n  bitvec_copy(tmp, x);\n\n  /* LSB set? Then start with x */\n  if (bitvec_get_bit(y, 0) != 0)\n  {\n    bitvec_copy(z, x);\n  }\n  else /* .. or else start with zero */\n  {\n    bitvec_set_zero(z);\n  }\n\n  /* Then add 2^i * x for the rest */\n  for (i = 1; i < CURVE_DEGREE; ++i)\n  {\n    /* lshift 1 - doubling the value of tmp */\n    bitvec_lshift(tmp, tmp, 1);\n\n    /* Modulo reduction polynomial if degree(tmp) > CURVE_DEGREE */\n    if (bitvec_get_bit(tmp, CURVE_DEGREE))\n    {\n      gf2field_add(tmp, tmp, polynomial);\n    }\n#if defined(CONST_TIME) && (CONST_TIME == 1)\n    else /* blinding operation */\n    {\n      gf2field_add(tmp, tmp, blind);\n    }\n#endif\n\n    /* Add 2^i * tmp if this factor in y is non-zero */\n    if (bitvec_get_bit(y, i))\n    {\n      gf2field_add(z, z, tmp);\n    }\n#if defined(CONST_TIME) && (CONST_TIME == 1)\n    else /* blinding operation */\n    {\n      gf2field_add(z, z, blind);\n    }\n#endif\n  }\n}\n\n/* field inversion 'z := 1/x' */\nstatic void gf2field_inv(gf2elem_t z, const gf2elem_t x)\n{\n  gf2elem_t u, v, g, h;\n  int i;\n\n  bitvec_copy(u, x);\n  bitvec_copy(v, polynomial);\n  bitvec_set_zero(g);\n  gf2field_set_one(z);\n  \n  while (!gf2field_is_one(u))\n  {\n    i = (bitvec_degree(u) - bitvec_degree(v));\n\n    if (i < 0)\n    {\n      bitvec_swap(u, v);\n      bitvec_swap(g, z);\n      i = -i;\n    }\n#if defined(CONST_TIME) && (CONST_TIME == 1)\n    else\n    {\n      bitvec_swap(u, v);\n      bitvec_swap(v, u);\n    }\n#endif\n    bitvec_lshift(h, v, i);\n    gf2field_add(u, u, h);\n    bitvec_lshift(h, g, i);\n    gf2field_add(z, z, h);\n  }\n}\n\n/*************************************************************************************************/\n/*\n   The following code takes care of Galois-Field arithmetic. \n   Elliptic curve points are represented  by pairs (x,y) of bitvec_t. \n   It is assumed that curve coefficient 'a' is {0,1}\n   This is the case for all NIST binary curves.\n   Coefficient 'b' is given in 'coeff_b'.\n   '(base_x, base_y)' is a point that generates a large prime order group.\n*/\n/*************************************************************************************************/\n\n\nstatic void gf2point_copy(gf2elem_t x1, gf2elem_t y1, const gf2elem_t x2, const gf2elem_t y2)\n{\n  bitvec_copy(x1, x2);\n  bitvec_copy(y1, y2);\n}\n\nstatic void gf2point_set_zero(gf2elem_t x, gf2elem_t y)\n{\n  bitvec_set_zero(x);\n  bitvec_set_zero(y);\n}\n\nstatic int gf2point_is_zero(const gf2elem_t x, const gf2elem_t y)\n{\n  return (    bitvec_is_zero(x)\n           && bitvec_is_zero(y));\n}\n\n/* double the point (x,y) */\nstatic void gf2point_double(gf2elem_t x, gf2elem_t y)\n{\n  /* iff P = O (zero or infinity): 2 * P = P */\n  if (bitvec_is_zero(x))\n  {\n    bitvec_set_zero(y);\n  }\n  else\n  {\n    gf2elem_t l;\n\n    gf2field_inv(l, x);\n    gf2field_mul(l, l, y);\n    gf2field_add(l, l, x);\n    gf2field_mul(y, x, x);\n    gf2field_mul(x, l, l);\n#if (coeff_a == 1)\n    gf2field_inc(l);\n#endif\n    gf2field_add(x, x, l);\n    gf2field_mul(l, l, x);\n    gf2field_add(y, y, l);\n  }\n}\n\n\n/* add two points together (x1, y1) := (x1, y1) + (x2, y2) */\nstatic void gf2point_add(gf2elem_t x1, gf2elem_t y1, const gf2elem_t x2, const gf2elem_t y2)\n{\n  if (!gf2point_is_zero(x2, y2))\n  {\n    if (gf2point_is_zero(x1, y1))\n    {\n      gf2point_copy(x1, y1, x2, y2);\n    }\n    else\n    {\n      if (bitvec_equal(x1, x2))\n      {\n        if (bitvec_equal(y1, y2))\n        {\n          gf2point_double(x1, y1);\n        }\n        else\n        {\n          gf2point_set_zero(x1, y1);\n        }\n      }\n      else\n      {\n        /* Arithmetic with temporary variables */\n        gf2elem_t a, b, c, d;\n\n        gf2field_add(a, y1, y2);\n        gf2field_add(b, x1, x2);\n        gf2field_inv(c, b);\n        gf2field_mul(c, c, a);\n        gf2field_mul(d, c, c);\n        gf2field_add(d, d, c);\n        gf2field_add(d, d, b);\n#if (coeff_a == 1)\n        gf2field_inc(d);\n#endif\n        gf2field_add(x1, x1, d);\n        gf2field_mul(a, x1, c);\n        gf2field_add(a, a, d);\n        gf2field_add(y1, y1, a);\n        bitvec_copy(x1, d);\n      }\n    }\n  }\n}\n\n\n\n#if defined(CONST_TIME) && (CONST_TIME == 0)\n/* point multiplication via double-and-add algorithm */\nstatic void gf2point_mul(gf2elem_t x, gf2elem_t y, const scalar_t exp)\n{\n  gf2elem_t tmpx, tmpy;\n  int i;\n  int nbits = bitvec_degree(exp);\n\n  gf2point_set_zero(tmpx, tmpy);\n\n  for (i = (nbits - 1); i >= 0; --i)\n  {\n    gf2point_double(tmpx, tmpy);\n    if (bitvec_get_bit(exp, i))\n    {\n      gf2point_add(tmpx, tmpy, x, y);\n    }\n  }\n  gf2point_copy(x, y, tmpx, tmpy);\n}\n#else\n/* point multiplication via double-and-add-always algorithm using scalar blinding */\nstatic void gf2point_mul(gf2elem_t x, gf2elem_t y, const scalar_t exp)\n{\n  gf2elem_t tmpx, tmpy;\n  gf2elem_t dummyx, dummyy;\n  int i;\n  int nbits = bitvec_degree(exp);\n\n  gf2point_set_zero(tmpx, tmpy);\n  gf2point_set_zero(dummyx, dummyy);\n\n  for (i = (nbits - 1); i >= 0; --i)\n  {\n    gf2point_double(tmpx, tmpy);\n\n    /* Add point if bit(i) is set in exp */\n    if (bitvec_get_bit(exp, i))\n    {\n      gf2point_add(tmpx, tmpy, x, y);\n    }\n    /* .. or add the neutral element to keep operation constant-time */\n    else\n    {\n      gf2point_add(tmpx, tmpy, dummyx, dummyy);\n    }\n  }\n  gf2point_copy(x, y, tmpx, tmpy);\n}\n#endif\n\n\n\n/* check if y^2 + x*y = x^3 + a*x^2 + coeff_b holds */\nstatic int gf2point_on_curve(const gf2elem_t x, const gf2elem_t y)\n{\n  gf2elem_t a, b;\n\n  if (gf2point_is_zero(x, y))\n  {\n    return 1;\n  }\n  else\n  {\n    gf2field_mul(a, x, x);\n#if (coeff_a == 0)\n    gf2field_mul(a, a, x);\n#else\n    gf2field_mul(b, a, x);\n    gf2field_add(a, a, b);\n#endif\n    gf2field_add(a, a, coeff_b);\n    gf2field_mul(b, y, y);\n    gf2field_add(a, a, b);\n    gf2field_mul(b, x, y);\n\n    return bitvec_equal(a, b);\n  }\n}\n\n\n/*************************************************************************************************/\n/*\n  Elliptic Curve Diffie-Hellman key exchange protocol.\n*/\n/*************************************************************************************************/\n\n\n\n/* NOTE: private should contain random data a-priori! */\nint ecdh_generate_keys(uint8_t* public_key, const uint8_t* private_key)\n{\n  /* Get copy of \"base\" point 'G' */\n  gf2point_copy((uint32_t*)public_key, (uint32_t*)(public_key + BITVEC_NBYTES), base_x, base_y);\n\n  /* Abort key generation if random number is too small */\n  if (bitvec_degree((uint32_t*)private_key) < (CURVE_DEGREE / 2))\n  {\n    return 0;\n  }\n  else\n  {\n    /* Clear bits > CURVE_DEGREE in highest word to satisfy constraint 1 <= exp < n. */\n    int nbits = bitvec_degree(base_order);\n    int i;\n\n    for (i = (nbits - 1); i < (BITVEC_NWORDS * 32); ++i)\n    {\n      bitvec_clr_bit((uint32_t*)private_key, i);\n    }\n\n    /* Multiply base-point with scalar (private-key) */\n    gf2point_mul((uint32_t*)public_key, (uint32_t*)(public_key + BITVEC_NBYTES), (uint32_t*)private_key);\n\n    return 1;\n  }\n}\n\n\n\nint ecdh_shared_secret(const uint8_t* private_key, const uint8_t* others_pub, uint8_t* output)\n{\n  /* Do some basic validation of other party's public key */\n  if (    !gf2point_is_zero ((uint32_t*)others_pub, (uint32_t*)(others_pub + BITVEC_NBYTES))\n       &&  gf2point_on_curve((uint32_t*)others_pub, (uint32_t*)(others_pub + BITVEC_NBYTES)) )\n  {\n    /* Copy other side's public key to output */\n    unsigned int i;\n    for (i = 0; i < (BITVEC_NBYTES * 2); ++i)\n    {\n      output[i] = others_pub[i];\n    }\n\n    /* Multiply other side's public key with own private key */\n    gf2point_mul((uint32_t*)output,(uint32_t*)(output + BITVEC_NBYTES), (const uint32_t*)private_key);\n\n    /* Multiply outcome by cofactor if using ECC CDH-variant: */\n#if defined(ECDH_COFACTOR_VARIANT) && (ECDH_COFACTOR_VARIANT == 1)\n #if   (cofactor == 2)\n    gf2point_double((uint32_t*)output, (uint32_t*)(output + BITVEC_NBYTES));\n #elif (cofactor == 4)\n    gf2point_double((uint32_t*)output, (uint32_t*)(output + BITVEC_NBYTES));\n    gf2point_double((uint32_t*)output, (uint32_t*)(output + BITVEC_NBYTES));\n #endif\n#endif\n    \n    return 1;\n  }\n  else\n  {\n    return 0;\n  }\n}\n\n\n/* ECDSA is broken :( ... */\nint ecdsa_sign(const uint8_t* private_key, uint8_t* hash, uint8_t* random_k, uint8_t* signature)\n{\n  /*\n     1) calculate e = HASH(m)\n     2) let z be the Ln leftmost bits of e, where Ln is the bit length of the group order n\n     3) Select a cryptographically secure random integer k from [1, n-1]\n     4) Calculate the curve point (x1, y1) = k * G\n     5) Calculate r = x1 mod n - if (r == 0) goto 3\n     6) Calculate s = inv(k) * (z + r * d) mod n - if (s == 0) goto 3\n     7) The signature is the pair (r, s)\n  */\n  assert(private_key != 0);\n  assert(hash != 0);\n  assert(random_k != 0);\n  assert(signature != 0);\n\n  int success = 0;\n\n  if (    (bitvec_degree((uint32_t*)private_key) >= (CURVE_DEGREE / 2))\n       && !bitvec_is_zero((uint32_t*)random_k) )\n  {\n    gf2elem_t r, s, z, k;\n\n    bitvec_set_zero(r);\n    bitvec_set_zero(s);\n    bitvec_copy(z, (uint32_t*)hash);\n\n    /* 1 + 2 */\n    int nbits = bitvec_degree(base_order);\n    int i;\n    for (i = (nbits - 1); i < BITVEC_NBITS; ++i)\n    {\n      bitvec_clr_bit(z, i);\n    }\n\n    /* 3 */\n    bitvec_copy(k, (uint32_t*)random_k);\n\n    /* 4 */\n    gf2point_copy(r, s, base_x, base_y);\n    gf2point_mul(r, s, k);\n\n    /* 5 */\n    if (!bitvec_is_zero(r))\n    {\n      /* 6) s = inv(k) * (z + (r * d)) mod n ==> if (s == 0) goto 3 **/\n      gf2field_inv(s, k);                     /* s = inv(k) */\n      gf2field_mul(r, r, (uint32_t*)private_key); /* r = (r * d) */\n      gf2field_add(r, r, z);                  /* r = z + (r * d) */\n\n      nbits = bitvec_degree(r); /* r = r mod n */\n      for (i = (nbits - 1); i < BITVEC_NBITS; ++i)\n      {\n        printf(\"reduction r\\n\");\n        bitvec_clr_bit(r, i);\n      }\n      \n      gf2field_mul(s, s, r);                  /* s = inv(k) * (z * (r * d)) */\n\n      nbits = bitvec_degree(s); /* s = s mod n */\n      for (i = (nbits - 1); i < BITVEC_NBITS; ++i)\n      {\n        printf(\"reduction s\\n\");\n        bitvec_clr_bit(s, i);\n      }\n\n      if (!bitvec_is_zero(s))\n      {\n        bitvec_copy((uint32_t*)signature, r);\n        bitvec_copy((uint32_t*)(signature + ECC_PRV_KEY_SIZE), s);\n        success = 1;\n      }\n    }\n  }\n  return success;\n}\n\n\nint ecdsa_verify(const uint8_t* public_key, uint8_t* hash, const uint8_t* signature)\n{\n  /*\n    1) Verify that (r,s) are in [1, n-1]\n    2) e = HASH(m)\n    3) z = Ln leftmost bits of e\n    4) w = inv(s) mod n\n    5) u1 = (z * w) mod n\n       u2 = (r * w) mod n\n    6) (x,y) = (u1 * G) + (u2 * public)\n    7) Signature is valid if r == x mod n && (x,y) != (0,0)\n  */\n  assert(public_key != 0);\n  assert(hash != 0);\n  assert(signature != 0);\n\n  int success = 0;\n\n  gf2elem_t r, s;\n  bitvec_copy(r, (uint32_t*)(signature));\n  bitvec_copy(s, (uint32_t*)(signature + ECC_PRV_KEY_SIZE));\n\n  if (    !bitvec_is_zero(s)\n       && !bitvec_is_zero(r))\n  {\n    gf2elem_t x1, y1, u1, u2, w, z;\n\n    /* 3) z = Ln leftmost bits of e */\n    bitvec_copy(z, (uint32_t*)hash); /* r,s,z are set */\n    uint32_t nbits = bitvec_degree(base_order);\n    uint32_t i;\n    for (i = (nbits - 1); i < BITVEC_NBITS; ++i)\n    {\n      bitvec_clr_bit(z, i);\n    }\n    \n    /* 4) w = inv(s) mod n */\n    gf2field_inv(w, s); /* w = inv(s) */\n    /* Modulo reduction polynomial if degree(tmp) > CURVE_DEGREE */\n    if (bitvec_get_bit(w, CURVE_DEGREE))\n    {\n      printf(\"reduction on w\\n\");\n      gf2field_add(w, w, polynomial);\n    }\n\n    /* 5) u1 = zw mod n, u2 = rw mod n*/\n    gf2field_mul(u1, z, w); /* u1 = z * w */\n    /* Modulo reduction polynomial if degree(tmp) > CURVE_DEGREE */\n    if (bitvec_get_bit(u1, CURVE_DEGREE))\n    {\n      printf(\"reduction on u1\\n\");\n      gf2field_add(u1, u1, polynomial);\n    }\n    gf2field_mul(u2, r, w); /* u2 = r * w */\n    /* Modulo reduction polynomial if degree(tmp) > CURVE_DEGREE */\n    if (bitvec_get_bit(u2, CURVE_DEGREE))\n    {\n      printf(\"reduction on u2\\n\");\n      gf2field_add(u2, u2, polynomial);\n    }\n\n    /* 6) (x,y) = (u1 * G) + (u2 * public) */\n    bitvec_copy(x1, base_x);\n    bitvec_copy(y1, base_y);\n    gf2field_mul(u1, x1, y1);  /* u1 * G */\n\n    bitvec_copy(w, (uint32_t*)(public_key));\n    bitvec_copy(z, (uint32_t*)(public_key + ECC_PRV_KEY_SIZE));\n    gf2field_mul(u2, w, z); /* u2 * Q */\n\n    \n    gf2point_add(x1, y1, w, z);\n    if (bitvec_get_bit(x1, CURVE_DEGREE))\n    {\n      printf(\"reduction on x1\\n\");\n      gf2field_add(x1, x1, polynomial);\n    }\n\n    success = bitvec_equal(r, x1);\n\n    if (!success)\n    {\n      printf(\"x = '\");\n      for (i = 0; i < BITVEC_NWORDS; ++i)\n      {\n        printf(\"%.08x\", x1[i]);\n      }\n      printf(\"' [%u]\\n\", i);\n      printf(\"r = '\");\n      for (i = 0; i < BITVEC_NWORDS; ++i)\n      {\n        printf(\"%.08x\", r[i]);\n      }\n      printf(\"' [%u]\\n\", i);\n    }\n  }\n  else\n  {\n    printf(\"(s or r) == zero\\n\");\n  }\n\n  return success;\n}\n\n#endif // ECDH_C\n\n\n"
  },
  {
    "path": "vault/net_fragment.c",
    "content": "// fragment data\n// - rlyeh, public domain\n//\n// ## fragment format\n// [fragnum:16][fraglen:16][crc:32][protocol-id(*):32][fragment-data:XX][eof:8]\n//   fragment-number: 000,001,002...\n//   fragment-length: end of stream if length < 65535\n//   crc: crc32 made of protocol-id+fragment-data\n//   protocol-id: used to calc crc of fragment-data only; never written or sent (*)\n//   fragment-data: user data; likely crypted\n//   end-of-fragment: least byte (lsb) from crc32. must match.\n\n#ifndef FRAGMENT_H\n#define FRAGMENT_H\n\nint   fragment_num(int msglen); // number of total fragments required for a full split\nchar* fragment_split(int fragment_seq, const void *msg, int msglen); // split one frag\nint   fragment_sizeof(int fragment_seq, int msglen); // size of specific fragment\n\nint   fragment_verify(array(char*) fragments);\nchar* fragment_join(array(char*) fragments);\n\n#endif\n\n#ifdef FRAGMENT_C\n#pragma once\n\n#define FRAGMENT_VERSION 0x595c7b10 // crc32(\"0.0.1\")\n#define FRAGMENT_MAXSIZE 65536      // 4 or 8 for testing\n//#define FRAGMENT_PREALLOCATE         // @todo\n\n#pragma pack(push, 1)\ntypedef struct fragment_header {\n    uint16_t fragment_seq;\n    uint16_t fragment_len;\n    uint32_t crc;\n    char     fragment_bin[];\n} fragment_header;\n#pragma pack(pop)\n\nint fragment_num(int msglen) {\n    return 1 + (msglen / FRAGMENT_MAXSIZE);\n}\nint fragment_sizeof(int fragment_seq, int msglen) {\n    int chunklen = fragment_seq == (fragment_num(msglen)-1) ? (msglen % FRAGMENT_MAXSIZE) : FRAGMENT_MAXSIZE;\n    return 8 + chunklen + 1;\n}\nchar* fragment_split(int fragment_seq, const void *msg, int msglen) {\n    uint16_t fragment_len = (uint16_t)(fragment_sizeof(fragment_seq, msglen) - 8 - 1);\n\n    // relocate pointer in msg\n    msg = ((const char*)msg) + fragment_seq * FRAGMENT_MAXSIZE;\n    uint32_t crc = crc32(FRAGMENT_VERSION, msg, fragment_len);\n\n    // prepare header\n    fragment_header header = { (uint16_t)fragment_seq, fragment_len, crc };\n\n    // store header + msg\n    char *fragment_buf = va(\"%*.s\", 8 + fragment_len + 1, \"\"); // FRAGMENT_PREALLOCATE\n    memcpy(fragment_buf, &header, sizeof(struct fragment_header));\n    memcpy(fragment_buf + 8, msg, fragment_len);\n    fragment_buf[8 + fragment_len] = header.crc & 0xFF;\n\n    return fragment_buf;\n}\n\n// returns +N if fragment Nth has checksum error (@todo)\n// returns  0 if ok\n// returns -N if fragment Nth is missing (@todo)\nint fragment_verify(array(char*) fragments) {\n    // 1. check that all fragments are present, and no dupes are found.\n    // 2. check that fragments are not truncated\n    // 3. check that fragments pass crc\n    int errcode = 0, quotient = -1;\n    int num_fragments = array_count(fragments);\n    char *present = CALLOC(1, num_fragments);\n    for( int i = 0; i < num_fragments; ++i ) {\n        fragment_header *ph = (fragment_header*)fragments[i];\n        if( ph->fragment_seq >= num_fragments ) { FREE(present); return -1; }; // incomplete\n        if( present[ph->fragment_seq] ) { FREE(present); return -1; }; // dupe\n        if( ph->fragment_bin[-4] != ph->fragment_bin[ph->fragment_len] ) { FREE(present); return -1; }; // truncated. @todo: endian (-1)\n        if( ph->crc != crc32(FRAGMENT_VERSION, ph->fragment_bin, ph->fragment_len) ) { FREE(present); return -1; }; // crc mismatch\n        if( ph->fragment_len < FRAGMENT_MAXSIZE ) if( quotient < 0 ) quotient = ph->fragment_len; else { FREE(present); return -1; } // dupe eof\n\n        present[ph->fragment_seq] = 1; // pass\n    }\n    FREE(present);\n    return 0;\n}\n\nchar* fragment_join(array(char*) fragments) {\n    if( fragment_verify(fragments) != 0 ) return 0;\n\n    static __thread char *ptr[16] = {0};\n    static __thread int slot = 0;\n    slot = (slot + 1) % 16;\n    int num_fragments = array_count(fragments);\n    ptr[slot] = REALLOC(ptr[slot], num_fragments * FRAGMENT_MAXSIZE); // worst case\n    for( int i = 0; i < num_fragments; ++i ) {\n        fragment_header *ph = (fragment_header*)fragments[i];\n        size_t offset = ph->fragment_seq * FRAGMENT_MAXSIZE;\n        memcpy( ptr[slot] + offset, ph->fragment_bin, ph->fragment_len );\n    }\n    return ptr[slot];\n}\n\n#ifdef FRAGMENT_DEMO\nint main() {\n    const char *msg = \"hello world\";\n    int msglen = 12;\n\n    array(char*) fragments = 0;\n    for( int i = 0; i < fragment_num(msglen); ++i ) {\n        char *fragment = fragment_split(i, msg, msglen);\n        int fraglen = fragment_sizeof(i, msglen);\n        hexdump(fragment, fraglen);\n\n        array_push(fragments, fragment);\n    }\n\n    assert(fragment_verify(fragments) == 0);\n    puts(fragment_join(fragments));\n    assert(~puts(\"Ok\"));\n}\n#endif // FRAGMENT_DEMO\n#endif // FRAGMENT_C\n"
  },
  {
    "path": "vault/net_tunnel.c",
    "content": "// crypted transport\n// 1. public handshake (ecdh) -> shared secret\n// 2. private tunnel (arc4 crypted)\n// - rlyeh, public domain\n\n#ifdef CORE_C\nvoid handshake_server(const char *port) {\n\n}\nvoid handshake_client(const char *address, const char *port) {\n\n}\n#endif\n"
  },
  {
    "path": "vault/net_webserver.c",
    "content": "// webserver, forked from nweb23.c by Nigel Griffiths (public domain).\n// - rlyeh, public domain.\n\n#ifndef WEBSERVER_H\n#define WEBSERVER_H\n\nint webserver(int port, const char *folder);\n\n#endif\n\n// -----------------------------------------------------------------------------\n\n#ifdef WEBSERVER_C\n#pragma once\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdbool.h>\n#include <string.h>\n\n#include <errno.h>\n#include <fcntl.h>\n#include <sys/types.h>\n\nconst char index_html[] =\n    // markdeep begin\n    \"<meta charset='utf-8' emacsmode='-*- markdown -*-'>\" \\\n    \"<link rel='stylesheet' href='https://casual-effects.com/markdeep/latest/apidoc.css?'>\" \\\n    \"<style>.backtick, .tilde {overflow-x: auto;} .longTOC {overflow-x: hidden;}</style>\"\n    // content\n    \"# hello\\n\"\n    \" - webserver.c\\n\"\n    // markdeep end\n    \"<script>markdeepOptions={tocStyle:'long'};</script>\" \\\n    \"<!-- Markdeep: --><script src='https://casual-effects.com/markdeep/latest/markdeep.min.js?'></script>\";\n\n\n#define WEB_VERSION    23\n#define WEB_BUFSIZE  8096\n#define WEB_ERROR      42\n#define WEB_LOG        44\n#define WEB_FORBIDDEN 403\n#define WEB_NOTFOUND  404\n\n#define WEB_GENERIC_MIME \"application/octet-stream\"\n\nstruct {\n    char *ext;\n    char *filetype;\n} extensions [] = {\n    {\"gif\", \"image/gif\" },\n    {\"jpg\", \"image/jpg\" },\n    {\"jpeg\", \"image/jpeg\"},\n    {\"png\", \"image/png\" },\n    {\"ico\", \"image/ico\" },\n    {\"zip\", \"image/zip\" },\n    {\"gz\",  \"image/gz\"  },\n    {\"tar\", \"image/tar\" },\n    {\"htm\", \"text/html\" },\n    {\"html\", \"text/html\" },\n    {0, 0}\n};\n\n#define webpanic(...) do { LOG(WEB|SERVER, __VA_ARGS__); exit(-1); } while(0)\n\n#define weblogger(...) do { if(!weblogger(__VA_ARGS__)) goto clean_up; } while(0)\nbool (weblogger)(int type, const char *s1, const char *s2, int socket_fd) {\n    int fd;\n    char logbuffer[WEB_BUFSIZE * 2];\n    const char *notfound = \"HTTP/1.1 404 Not Found\\nContent-Length: 138\\nConnection: close\\nContent-Type: text/html\\n\\n<html><head>\\n<title>404 Not Found</title>\\n</head><body>\\n<h1>Not Found</h1>\\nThe requested URL was not found on this server.\\n</body></html>\\n\";\n    const char *forbidden = \"HTTP/1.1 403 Forbidden\\nContent-Length: 185\\nConnection: close\\nContent-Type: text/html\\n\\n<html><head>\\n<title>403 Forbidden</title>\\n</head><body>\\n<h1>Forbidden</h1>\\nThe requested URL, file type or operation is not allowed on this simple static file webserver.\\n</body></html>\\n\";\n    /**/ if( type == WEB_LOG) { sprintf(logbuffer, \" INFO: %s:%s:%d\", s1, s2, socket_fd); }\n    else if( type == WEB_ERROR) { sprintf(logbuffer, \"WEB_ERROR: %s:%s Errno=%d exiting pid=%d\", s1, s2, errno, getpid()); }\n    else if( type == WEB_NOTFOUND) { tcp_send(socket_fd, notfound, 224); sprintf(logbuffer, \"NOT FOUND: %s:%s\", s1, s2); }\n    else if( type == WEB_FORBIDDEN) { tcp_send(socket_fd, forbidden, 271); sprintf(logbuffer, \"WEB_FORBIDDEN: %s:%s\", s1, s2); }\n    /* No checks here, nothing can be done with a failure anyway */\n    LOG(WEB|HOST, logbuffer);\n    return (type == WEB_ERROR || type == WEB_NOTFOUND || type == WEB_FORBIDDEN) ? false : true;\n}\n\n/* this is a child web server process, so we can exit on errors */\nstatic __thread int hit = 0;\nstatic\nint nweb23(int fd) {\n    int j, buflen;\n    long i, ret, len;\n    char *fstr;\n    static char buffer[WEB_BUFSIZE + 1]; /* static so zero filled */\n\n    ret = tcp_recv(fd, buffer, WEB_BUFSIZE); /* read Web request in one go */\n    if(ret == 0 || ret == -1)    /* read failure stop now */ {\n        weblogger(WEB_FORBIDDEN, \"failed to read browser request\", \"\", fd);\n    }\n    if(ret > 0 && ret < WEB_BUFSIZE)  /* return code is valid chars */\n        buffer[ret] = 0;  /* terminate the buffer */\n    else buffer[0] = 0;\n    for(i = 0; i < ret; i++) /* remove CF and LF characters */\n        if(buffer[i] == '\\r' || buffer[i] == '\\n')\n            buffer[i] = '*';\n    weblogger(WEB_LOG, \"request\", buffer, hit);\n    if( strncmp(buffer, \"GET \", 4) && strncmp(buffer, \"get \", 4) ) {\n        weblogger(WEB_FORBIDDEN, \"Only simple GET operation supported\", buffer, fd);\n    }\n    for(i = 4; i < WEB_BUFSIZE; i++) /* null terminate after the second space to ignore extra stuff */ {\n        if(buffer[i] == ' ')   /* string is \"GET URL \" +lots of other stuff */ {\n            buffer[i] = 0;\n            break;\n        }\n    }\n    for(j = 0; j < i - 1; j++) /* check for illegal parent directory use .. */\n        if(buffer[j] == '.' && buffer[j + 1] == '.') {\n            weblogger(WEB_FORBIDDEN, \"Parent directory (..) path names not supported\", buffer, fd);\n        }\n    if( !strncmp(&buffer[0], \"GET /\\0\", 6) || !strncmp(&buffer[0], \"get /\\0\", 6) ) /* convert no filename to index file */\n        strcpy(buffer, \"GET /index.html\");\n\n    /* work out the file type and check we support it */\n    buflen = strlen(buffer);\n    fstr = (char *)0;\n    for(i = 0; extensions[i].ext != 0; i++) {\n        len = strlen(extensions[i].ext);\n        if( !strncmp(&buffer[buflen - len], extensions[i].ext, len)) {\n            fstr = extensions[i].filetype;\n            break;\n        }\n    }\n    if(fstr == 0) {\n        //weblogger(WEB_FORBIDDEN, \"file extension type not supported\", buffer, fd);\n        fstr = WEB_GENERIC_MIME;\n    }\n\n    const char *fname = &buffer[5];\n\n    if( !strcmp(fname, \"index.html\") ) {\n        len = strlen(index_html);\n\n        weblogger(WEB_LOG, \"Header\", buffer, hit);\n        sprintf(buffer, \"HTTP/1.1 200 OK\\nServer: net.webserver/%d.0\\nContent-Length: %ld\\nConnection: close\\nContent-Type: %s\\n\\n\", WEB_VERSION, len, fstr); /* Header + a blank line */\n        tcp_send(fd, buffer, strlen(buffer));\n\n        /* send file in 8KB block - last block may be smaller */\n        const char *ptr = index_html, *end = ptr + len;\n        while( ptr < end ) {\n            tcp_send(fd, ptr, (ptr + WEB_BUFSIZE) >= end ? end - ptr : WEB_BUFSIZE);\n            ptr += WEB_BUFSIZE;\n        }\n        goto clean_up;\n    }\n\n    // open the file for reading\n    FILE *file_fd = fopen(fname, \"rb\");\n    if( file_fd ) {\n        fseek(file_fd, (off_t)0, SEEK_END); /* lseek to the file end to find the length */\n        len = (long)ftell(file_fd);\n        fseek(file_fd, (off_t)0, SEEK_SET); /* lseek back to the file start ready for reading */\n\n        weblogger(WEB_LOG, \"Header\", buffer, hit);\n        sprintf(buffer, \"HTTP/1.1 200 OK\\nServer: net.webserver/%d.0\\nContent-Length: %ld\\nConnection: close\\nContent-Type: %s\\n\\n\", WEB_VERSION, len, fstr); /* Header + a blank line */\n        tcp_send(fd, buffer, strlen(buffer));\n\n        /* send file in 8KB block - last block may be smaller */\n        weblogger(WEB_LOG, \"SEND\", fname, hit);\n        while (  (ret = fread(buffer, 1, WEB_BUFSIZE, file_fd)) > 0 ) {\n            tcp_send(fd, buffer, ret);\n        }\n        fclose(file_fd);\n    } else {\n        weblogger(WEB_NOTFOUND, \"failed to open file\", fname, fd);\n    }\n\n    clean_up:;\n\n    /* allow socket to drain before signalling the socket is closed */\n    sleep_ss(1);\n    tcp_close(fd);\n\n    return 0;\n}\n\n#undef weblogger\n\n\nint webserver(int port, const char *path) {\n    /* input checks */\n    if( port < 1024 || port > 60000) {\n        webpanic(\"!Invalid port number (try 1024<port<60000)\");\n    }\n    if( !strncmp(path, \"/\"   , 2 ) || !strncmp(path, \"/etc\", 5 ) ||\n        !strncmp(path, \"/bin\", 5 ) || !strncmp(path, \"/lib\", 5 ) ||\n        !strncmp(path, \"/tmp\", 5 ) || !strncmp(path, \"/usr\", 5 ) ||\n        !strncmp(path, \"/dev\", 5 ) || !strncmp(path, \"/sbin\", 6) ) {\n        webpanic(\"!Blacklisted top directory (use another folder)\");\n    }\n    if( chdir(path) < 0 ) {\n        webpanic(\"!Cannot change to directory\");\n    }\n\n    weblogger(WEB_LOG, \"host started\", \"\", getpid());\n\n    /* setup the network socket */\n    tcp_init();\n    int listenfd = tcp_bind(\"0.0.0.0\", va(\"%d\",port), 64), socketfd;\n    if( listenfd < 0 ) {\n        webpanic(\"!Cannot create listening socket\");\n    }\n    for(hit = 1; ; hit++) {\n        if(tcp_peek(listenfd,nweb23)) {}\n        sleep_ms(500);\n    }\n\n    clean_up:;\n    return 0;\n}\n\n#ifdef WEBSERVER_DEMO\nint main() {\n    puts(\"listening at http://localhost:8000\");\n    webserver(8000, \"./\");\n}\n#endif // WEBSERVER_DEMO\n#endif // WEBSERVER_C\n"
  },
  {
    "path": "vault/os.c",
    "content": "// [x] if/n/def hell + system headers: here, rather than in every header.\n// - rlyeh, public domain\n\n#ifndef OS_H\n#define OS_H\n\n#  if defined __ANDROID_API__\n#define _AND\n#elif defined __APPLE__\n#define _OSX\n#elif defined __FreeBSD__\n#define _BSD\n#elif defined _WIN32\n#define _WIN\n#else\n#define _LIN\n#endif\n\n#  if defined _MSC_VER\n#define _MSC\n#elif defined __clang__\n#define _CLA\n#elif defined __TINYC__\n#define _TCC\n#else\n#define _GCC\n#endif\n\n#ifdef _AND\n#include <dlfcn.h>\n#include <malloc.h>\nsize_t dlmalloc_usable_size(void*); // (android)\n#endif\n\n#ifdef _BSD\n#include <dlfcn.h>\n#include <malloc/malloc.h>\n#endif\n\n#ifdef _IOS\n#include <mach-o/dyld.h>\n#include <malloc/malloc.h>\n#endif\n\n#ifdef _LIN\n#include <dlfcn.h>\n#include <malloc.h>\n#endif\n\n#ifdef _OSX\n#include <mach-o/dyld.h>\n#include <malloc/malloc.h>\n#endif\n\n#ifdef _WIN\n#ifndef _WIN32_WINNT\n#define _WIN32_WINNT 0x0600 // for CONDITION_VARIABLE\n#endif\n#ifdef _TCC\n#include <io.h>\n#include <windows.h>\n#else\n#include <winsock2.h>\n#include <windows.h>\n#endif\n#include <malloc.h>\n#endif\n\n// augment vendor compatibility\n\n#ifndef __STDC_LIMIT_MACROS\n#define __STDC_LIMIT_MACROS // <stdint.h>: UINT32_MAX...\n#endif\n\n// all required standard headers\n\n#include <errno.h>\n#include <stdarg.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n// builtins\n\n#if !defined __thread && (defined _MSC || defined _TCC)\n#define __thread __declspec(thread)\n#endif\n\n#if !defined inline && defined _MSC && !defined __cplusplus\n#define inline _inline\n#endif\n\n// autorun initializers for C\n// - rlyeh, public domain\n//\n// note: based on code by Joe Lowe (public domain).\n// note: XIU for C initializers, XCU for C++ initializers, XTU for C deinitializers\n\n#ifndef AUTORUN\n    #ifdef __cplusplus\n    #define AUTORUN \\\n        static void AUTORUN_U(autorun)(void); \\\n        static const int AUTORUN_J(AUTORUN_U(autorun),__1) = (AUTORUN_U(autorun)(), 1); \\\n        static void AUTORUN_U(autorun)(void)\n    #elif defined _MSC\n    #define AUTORUN \\\n        static void AUTORUN_U(autorun)(void); \\\n        static int AUTORUN_J(AUTORUN_U(autorun),__1) (){ AUTORUN_U(autorun)(); return 0; } \\\n        __pragma(section(\".CRT$XIU\", long, read)) \\\n        __declspec(allocate(\".CRT$XIU\")) \\\n        static int(* AUTORUN_J(AUTORUN_U(autorun),__2) )() = AUTORUN_J(AUTORUN_U(autorun),__1); \\\n        static void AUTORUN_U(autorun)(void)\n    #else\n    #define AUTORUN \\\n        __attribute__((constructor)) \\\n        static void AUTORUN_U(autorun)(void)\n    #endif\n\n    // helpers: join + unique macros\n\n    #define AUTORUN_j(a, b) a##b\n    #define AUTORUN_J(a, b) AUTORUN_j(a, b)\n    #define AUTORUN_U(x)    AUTORUN_J(x, __LINE__)\n#endif\n\n#ifdef AUTORUN_DEMO\n    #include <stdio.h>\n    #include <stdlib.h>\n    int main() {\n        puts(\"during main()\");\n    }\n    void my_quit(void) {\n        puts(\"after main()\");\n    }\n    AUTORUN {\n        puts(\"before main() [1]\");\n    }\n    AUTORUN {\n        puts(\"before main() [2]\");\n        atexit( my_quit );\n    }\n    #define main main__\n#endif\n\n#endif // OS_H\n\n// -----------------------------------------------------------------------------\n\n#ifdef OS_C\n#define MEMORY_C\n#define DLL_C\n#define PLUGIN_C\n#define TIME_C\n#define TRACE_C\n#define PANIC_C\n#define ASSERT_C\n#define MIME_C\n#define FILE_C\n#define EXEC_C\n#define ICON_C\n#define TRAY_C\n#define SINGLETON_C\n#define ANSI_C\n#define ENTROPY_C\n#define INI_C\n#define TITLE_C\n#define ARGS_C\n#define EXIT_C\n#define ENV_C\n#define BREAKPOINT_C\n#define DIALOG_C\n#define DIE_C\n#define CPU_C\n#define DATE_C\n#define TRAP_C\n#define TEST_C\n#define LOGGER_C\n#define LOGGER2_C\n#define LOGGER3_C\n#define LOCALE_C\n#endif\n\n#include \"os_memory.c\"\n#include \"os_assert.c\"\n#include \"os_dll.c\"\n#include \"os_plugin.c\"\n#include \"os_time.c\"\n#include \"os_logger.c\"\n#include \"os_logger2.c\"\n#include \"os_trace.c\" // after os_logger\n#include \"os_die.c\"\n#include \"os_panic.c\"\n#include \"os_mime.c\"\n#include \"os_file.c\"\n#include \"os_exec.c\"\n#include \"os_icon.c\"\n#include \"os_tray.c\" // after os_icon\n#include \"os_singleton.c\"\n#include \"os_ansi.c\"\n#include \"os_entropy.c\"\n#include \"os_ini.c\"\n#include \"os_title.c\"\n#include \"os_args.c\"\n#include \"os_exit.c\"\n#include \"os_env.c\"\n#include \"os_breakpoint.c\"\n#include \"os_dialog.c\"\n#include \"os_cpu.c\"\n#include \"os_date.c\"\n#include \"os_trap.c\" // after os_panic\n#include \"os_test.c\"\n#include \"os_locale.c\"\n\n#include \"os_logger3.c\" // after os_logger2+os_trace+os_ansi\n"
  },
  {
    "path": "vault/os_ansi.c",
    "content": "// - rlyeh, public domain\n\nvoid os_ansi(void);\nvoid os_beep(void);\nvoid os_color(uint8_t r, uint8_t g, uint8_t b);\nvoid os_reset(void);\nint  os_columns(void);\n\n// ----------------------------------------------------------------------------\n\n#ifdef ANSI_C\n#pragma once\n\n#ifndef _WIN32\n#   include <sys/ioctl.h>\n#   include <termios.h>\n#   include <unistd.h>\n#endif\n\nint os_columns(void) {\n#ifdef _WIN32\n    CONSOLE_SCREEN_BUFFER_INFO csbi;\n    if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {\n        return csbi.srWindow.Right - csbi.srWindow.Left + 1; // Window width\n    }\n#elif defined(TIOCGSIZE)\n    struct ttysize ts;\n    ioctl(STDIN_FILENO, TIOCGSIZE, &ts);\n    return ts.ts_cols + 1;\n#elif defined(TIOCGWINSZ)\n    struct winsize ts;\n    ioctl(STDIN_FILENO, TIOCGWINSZ, &ts);\n    return ts.ws_col + 1;\n#endif\n    return 1;\n}\n\nvoid os_ansi(void) {\n#ifdef _WIN32\n    /* Best effort enable ANSI escape processing. */\n    HANDLE handle;\n    DWORD mode;\n    handle = GetStdHandle(-11); /* STD_OUTPUT_HANDLE */\n    if (GetConsoleMode(handle, &mode)) {\n        mode |= 0x0004; /* ENABLE_VIRTUAL_TERMINAL_PROCESSING */\n        SetConsoleMode(handle, mode); /* ignore errors */\n    }\n#endif\n}\n\nvoid os_beep(void) {\n    fputc('\\x7', stdout); // putc(0x7, stdout)\n}\n\nvoid os_reset(void) {\n    static int once = 0; if( !once ) { once = 1; atexit(os_reset); }\n#ifdef _WIN32\n    static CONSOLE_SCREEN_BUFFER_INFO csbi = {0}, *ever = 0;\n    if( !ever ) {\n        const HANDLE console = GetStdHandle( STD_OUTPUT_HANDLE );\n        if (console == INVALID_HANDLE_VALUE) {\n            return;\n        }\n        if (!GetConsoleScreenBufferInfo(console, &csbi)) {\n            return;\n        }\n        ever = &csbi;\n    }\n    const HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);\n    if (console != INVALID_HANDLE_VALUE) {\n        SetConsoleTextAttribute(console, csbi.wAttributes);\n    }\n#else\n    puts(\"\\x1B[39;49m\");\n#endif\n}\n\nvoid os_color(uint8_t r, uint8_t g, uint8_t b) {\n    static int once = 0; if( !once ) { once = 1; os_reset(); }\n#ifdef _WIN32\n    const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);\n    auto color = ( r > 127 ? FOREGROUND_RED : 0 ) |\n                 ( g > 127 ? FOREGROUND_GREEN : 0 ) |\n                 ( b > 127 ? FOREGROUND_BLUE : 0 );\n    if(!(r+g+b)) color=BACKGROUND_RED|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE; // bright white on red\n    SetConsoleTextAttribute(stdout_handle, color | FOREGROUND_INTENSITY);\n#else\n    if(!(r+g+b)) { printf(\"\\033[41;97m\"); return; } // bright white on red\n    // 24-bit console ESC[ … 38;2;<r>;<g>;<b> … m Select RGB foreground color\n    // 256-color console ESC[38;5;<fgcode>m\n    // 0x00-0x07:  standard colors (as in ESC [ 30..37 m)\n    // 0x08-0x0F:  high intensity colors (as in ESC [ 90..97 m)\n    // 0x10-0xE7:  6*6*6=216 colors: 16 + 36*r + 6*g + b (0≤r,g,b≤5)\n    // 0xE8-0xFF:  grayscale from black to white in 24 steps\n    r /= 51, g /= 51, b /= 51; // [0..5]\n    printf(\"\\033[38;5;%dm\", r*36+g*6+b+16); // \"\\033[0;3%sm\", color_code);\n#endif\n}\n\n#endif // OS_ANSI\n\n"
  },
  {
    "path": "vault/os_assert.c",
    "content": "// [x] assert: which works in release builds.\n// [x] test: test & autotest macros.\n// - rlyeh, public domain\n\n// ----------------------------------------------------------------------------\n\n#ifndef ASSERT_H\n#define ASSERT_H <assert.h>\n#endif\n\n#ifndef NDEBUG\n#   include ASSERT_H\n#else\n#   undef NDEBUG\n#   include ASSERT_H\n#   define NDEBUG\n#endif\n\n#ifdef SHIPPING\n#   undef  assert\n#   define assert(expr) (void)0\n#endif\n\n// ----------------------------------------------------------------------------\n\n#ifndef TEST_H\n#define TEST_H\n\nstatic __thread int tests = 0, fails = 0;\n\n#ifdef NDEBUG\n#define TEST(...) (void)0\n#define AUTOTEST  static void AUTORUN_U(unused_test)(void)\n#else\n#define TEST(...) (printf(\" #%02d (%s) %s:%d \", ++tests, #__VA_ARGS__, __FILE__, __LINE__), printf(\"\\r%c\\n\", \"NY\"[!!(__VA_ARGS__)]))\n#define AUTOTEST  AUTORUN\n#endif\n\n#endif\n"
  },
  {
    "path": "vault/os_breakpoint.c",
    "content": "void os_breakpoint();\n\n#ifdef BREAKPOINT_C\n#pragma once\n#include <signal.h>\n\nvoid os_breakpoint() {\n#if _MSC_VER\n    __debugbreak();    // msvc\n#elif __GNUC__\n    __builtin_trap();  // gcc and clang\n#else\n    raise(SIGTRAP);    // posix\n#endif\n}\n\n#ifdef BREAKPOINT_DEMO\n#include <stdio.h>\nint main() {\n    puts(\"trying to invoke debugger... (may crash if debugger is not attached)\");\n    os_breakpoint();\n}\n#endif\n#endif\n"
  },
  {
    "path": "vault/os_cpu.c",
    "content": "   int cpu_pid(void);\n   int cpu_cores(void);\ndouble cpu_usage(void);\n\n\n#ifdef CPU_DEMO\n#pragma once\n#ifdef _WIN32\n#include <windows.h>\nstatic ULONGLONG cpu_diff_time_(const FILETIME one, const FILETIME two) {\n    LARGE_INTEGER a, b;\n    a.LowPart = one.dwLowDateTime;\n    a.HighPart = one.dwHighDateTime;\n\n    b.LowPart = two.dwLowDateTime;\n    b.HighPart = two.dwHighDateTime;\n\n    return a.QuadPart - b.QuadPart;\n}\n#elif defined __linux__\n#include <sched.h>\n#else\n#include <unistd.h>\n#endif\n\n// CPU currently used by current process:\n// src: https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process\n// src: https://stackoverflow.com/questions/23143693/retrieving-cpu-load-percent-total-in-windows-with-c\n\ndouble cpu_usage(void) {\n#ifndef _WIN32\n    return 0;\n#else\n    static double last_ok = 0;\n    static FILETIME prevSysIdle, prevSysKernel, prevSysUser;\n\n    FILETIME sysIdle, sysKernel, sysUser;\n    // sysKernel include IdleTime\n    if (GetSystemTimes(&sysIdle, &sysKernel, &sysUser) == 0) { // GetSystemTimes func FAILED return value is zero;\n        return last_ok;\n    }\n\n    if (prevSysIdle.dwLowDateTime != 0 && prevSysIdle.dwHighDateTime != 0) {\n        ULONGLONG sysIdleDiff, sysKernelDiff, sysUserDiff;\n        sysIdleDiff = cpu_diff_time_(sysIdle, prevSysIdle);\n        sysKernelDiff = cpu_diff_time_(sysKernel, prevSysKernel);\n        sysUserDiff = cpu_diff_time_(sysUser, prevSysUser);\n\n        ULONGLONG sysTotal = sysKernelDiff + sysUserDiff;\n        ULONGLONG kernelTotal = sysKernelDiff - sysIdleDiff; // kernelTime - IdleTime = kernelTime, because sysKernel include IdleTime\n\n        if (sysTotal > 0) { // sometimes kernelTime > idleTime\n            last_ok = (double)(((kernelTotal + sysUserDiff) * 100.0) / sysTotal);\n        }\n    }\n\n    prevSysIdle = sysIdle;\n    prevSysKernel = sysKernel;\n    prevSysUser = sysUser;\n\n    return last_ok;\n#endif\n}\n\nint cpu_cores(void) {\n#if defined __cplusplus\n    return (int)std::thread::hardware_concurrency();\n#elif defined _WIN32\n    DWORD_PTR pm, sm;\n    if( GetProcessAffinityMask(GetCurrentProcess(), &pm, &sm) ) if( pm ) {\n        int count = 0;\n        while( pm ) {\n            ++count;\n            pm &= pm - 1;\n        }\n        return count;\n    }\n    { SYSTEM_INFO si; GetSystemInfo(&si); return (int)si.dwNumberOfProcessors; }\n#elif defined __linux__\n    cpu_set_t prevmask, testmask;\n    CPU_ZERO(&prevmask);\n    CPU_ZERO(&testmask);\n    sched_getaffinity(0, sizeof(prevmask), &prevmask);     //Get current mask\n    sched_setaffinity(0, sizeof(testmask), &testmask);     //Set zero mask\n    sched_getaffinity(0, sizeof(testmask), &testmask);     //Get mask for all CPUs\n    sched_setaffinity(0, sizeof(prevmask), &prevmask);     //Reset current mask\n    int num = CPU_COUNT(&testmask);\n    return (num > 1 ? num : 1);\n#elif defined __unix__\n    // unix\n    int count = sysconf(_SC_NPROCESSORS_ONLN);\n    return count > 0 ? count : 1;\n#else\n    // omp\n    int cores = 0;\n    #pragma omp parallel\n    {\n        #pragma omp atomic\n        ++cores;\n    }\n    return cores;\n#endif\n}\n\nint cpu_pid(void) {\n#ifdef _WIN32\n    return _getpid();\n#else\n    return getpid();\n#endif\n}\n\n#ifdef CPU_DEMO\n#include <stdio.h>\nint main() {\n    printf(\"process-id: %d\\n\", cpu_pid());\n    printf(\"%d cpus\\n\", cpu_cores());\n\n    for( int i = 0; i < 100000000; ++i) { float f = sqrt(1); }\n    printf(\"%5.2f%% usage\\n\", cpu_usage());\n}\n#define main main__\n#endif // CPU_DEMO\n#endif // CPU_C\n"
  },
  {
    "path": "vault/os_date.c",
    "content": "// base10 clock format\n// -------------------\n// Every base10 calendar is a 64-bit number, where:\n//\n// 18446744073709551615 <-- largest 64-bit number\n// *YYYMMDDhhmmssuuuuuu\n\n// - return current date & time in base10. date() = today_gmt() + time_us()\n// - return format base10 as string, where \"YYYY-MM-DD hh:mm:ss.uuuuuu W\" YYY since 2k, u = microseconds, W = day-of-week\n// - return adjusted system time (gmt)\n// - return unadjusted system time (ust)\n\nuint64_t date();\nchar *   date_format(uint64_t base10);\n\nuint64_t today_gmt();\nuint64_t today_ust();\n\n\n#ifdef DATE_C\n#pragma once\n#ifndef _WIN32\n#include <sys/time.h>\n#endif\n#include <time.h>\n\nstatic uint64_t date_base10(int64_t unixstamp) {\n    // Reference: Fliegel, H. F. and van Flandern, T. C. (1968).\n    // Communications of the ACM, Vol. 11, No. 10 (October, 1968).\n    enum { RTC_EPOCH_JULIAN_DAY = 2440588 }; // January 1st, 1970.\n    int64_t yy, mm, dd, l, n;\n    l = unixstamp / 86400 + 68569 + RTC_EPOCH_JULIAN_DAY;\n    n = 4 * l / 146097;\n    l = l - (146097 * n + 3) / 4;\n    yy = 4000 * (l + 1) / 1461001;\n    l = l - 1461 * yy / 4 + 31;\n    mm = 80 * l / 2447;\n    dd = l - 2447 * mm / 80;\n    l = mm / 11;\n    mm = mm + 2 - 12 * l;\n    yy = 100 * (n - 49) + yy + l;\n    yy -= 2000;\n\n    unixstamp = unixstamp % (24 * 3600);\n    int hh = (int)unixstamp / 3600;\n\n    unixstamp = unixstamp % 3600;\n    int mn = (int)unixstamp / 60;\n    int ss = (int)unixstamp % 60;\n\n#if 0\n    int id = (time_us() % 1000000);\n#elif 0\n    static uint8_t id = 0xFF; ++id;\n#else\n    const uint8_t id = 0;\n#endif\n\n    return\n    /// Every base10 calendar is a 64-bit number:\n    /// 18446744073709551615\n    /// *YYYMMDDhhmmssuuuuuu uuuuuu = microseconds\n    yy *   10000000000000000ULL +\n    mm *     100000000000000ULL +\n    dd *       1000000000000ULL +\n    hh *         10000000000ULL +\n    mn *           100000000ULL +\n    ss *             1000000ULL +\n    //                000000ULL;\n                             id;\n}\n\nuint64_t today_ust() {\n    return date_base10( time(0) );\n}\n\nuint64_t today_gmt() {\n    time_t t = time(0);\n    struct tm *gtm = gmtime(&t);\n    int hh1 = gtm->tm_hour, mm1 = gtm->tm_min;\n    struct tm *ltm = localtime(&t);\n    int hh2 = ltm->tm_hour, mm2 = ltm->tm_min;\n    int hdiff = hh2-hh1;\n    int mdiff = mm2-mm1;\n    return date_base10( time(0) + (1) * (hdiff * 3600 + mdiff * 60) );\n}\n\nuint64_t date() {\n    return today_gmt() + time_us() % 1000000;\n}\n\nchar *date_format( uint64_t base10 ) {\n    int y, m, d, dow;\n    int us = base10 % 1000000; base10 /= 1000000;\n    int ss = base10 %     100; base10 /= 100;\n    int mn = base10 %     100; base10 /= 100;\n    int hh = base10 %     100; base10 /= 100; d = base10 % 100;\n    int dd =                 d; base10 /= 100; m = base10 % 100;\n    int mm =                 m; base10 /= 100; y = base10 % 100;\n    int yy =                 y; base10 /= 100;\n    if( 1 ) {\n        /* Tomohiko Sakamoto's Algorithm */\n        /* Get day of the week [0=Sun..6=Sat]*/\n        int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};\n        dow = (y -= m < 3, (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7);\n    }\n    // return va(\"%04d-%02d-%02d %02d:%02d:%02d.%06d %d\", 2000 + yy, mm, dd, hh, mn, ss, us, dow);\n    static __thread char buf[320];\n    static __thread int slot = 0; slot = (slot + 1) % 10;\n    snprintf(buf + slot*32, 32, \"%04d-%02d-%02d %02d:%02d:%02d.%06d %d\", 2000 + yy, mm, dd, hh, mn, ss, us, dow);\n    return buf + slot*32;\n}\n\n#ifdef DATE_DEMO\n#include <stdio.h>\nint main() {\n    uint64_t gmt = today_gmt(); printf(\"gmt %019llu -> %s\\n\", gmt, date_format(gmt) );\n    uint64_t ust = today_ust(); printf(\"ust %019llu -> %s\\n\", ust, date_format(ust) );\n    // printf(\"%+lld adjust time\\n\", (gmt - ust) / 100000000);\n    while(1) {\n        printf(\"\\rnow %019llu -> %s\", date(), date_format(date()) );\n    }\n}\n#define main main__\n#endif // DATE_DEMO\n#endif // DATE_C\n"
  },
  {
    "path": "vault/os_dialog.c",
    "content": "// # dialog ###################################################################\n\nint os_dialog( int buttons, const char *title, const char *message );\n\n#ifdef DIALOG_C\n#pragma once\n\n#include <stdarg.h>\n#include <string.h>\n#include <stdbool.h>\n#include <stdlib.h>\n\n#ifdef _WIN32\n#include <winsock2.h>\n#ifdef __TINYC__\n    #define CP_UTF8 65001\n    int WINAPI MultiByteToWideChar();\n    int WINAPI WideCharToMultiByte();\n#else\n    #include <shlobj.h>\n#endif\nwchar_t *dialog_widen(wchar_t *buf, int sz, const char *utf8) { // wide strings (windows only)\n    int needed = 2 * MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);\n    buf[0] = 0;\n    if( needed < sz ) {\n        MultiByteToWideChar(CP_UTF8, 0, utf8, -1, (void*)buf, needed);\n    }\n    return (wchar_t *)buf;\n}\n#endif\n\nint os_dialog( int buttons, const char *title, const char *message ) {\n    title += title[0] == '!';     // advance text if starts with '!' (with callstack option)\n    message += message[0] == '!'; // advance text if starts with '!' (with callstack option)\n\n    char lower[256] = {0};\n    for( int i = 0; title[i]; ++i) lower[i] = title[i] | 32;\n\n    int is_fail = !!strstr(lower, \"fail\") || !!strstr(lower, \"error\") || !!strstr(lower, \"crash\");\n    int is_help = !!strstr(lower, \"help\") || !!strstr(lower, \"about\") || !!strstr(lower, \"info\");\n    int is_warn = !!strstr(lower, \"warning\");\n\n#if 0\n    if( is_fail || is_warn ) {\n        if(window) glfwSetClipboardString(window, message);\n    }\n#endif\n\n#ifdef _WIN32\n    #pragma comment(lib, \"user32\")\n    wchar_t buf1[256], buf2[2048];\n    wchar_t *title16 = dialog_widen(buf1, 256, title), *message16 = dialog_widen(buf2, 2048, message);\n    int rc = MessageBoxW(0, message16, title16, MB_SETFOREGROUND |\n        (buttons >= 3 ? MB_YESNOCANCEL : buttons >= 2 ? MB_YESNO : MB_OK) |\n        (is_fail ? MB_ICONERROR :\n        (is_warn ? MB_ICONWARNING :\n        (is_help ? MB_ICONQUESTION : 0)))\n    );\n    /**/ if( rc == IDYES || rc == IDOK ) return 1;\n    else if( rc == IDNO ) return 0;\n    return 2;\n#else\n    return 0;\n#endif\n}\n\n#ifdef DIALOG_DEMO\n#include <assert.h>\n#include <stdio.h>\nint main() {\n    int unicode = os_dialog(0, \"unicode test info dialog\", \"私 は ガ\");\n\n    int pressed1 = os_dialog(3, \"3-buttons general dialog\", \"Bla.\\nContinue?\");\n    int pressed2 = os_dialog(2, \"2-buttons warning dialog\", \"Bla.\\nContinue?\");\n    int pressed3 = os_dialog(1, \"1-button error dialog\", \"Bla.\\nBla.\");\n    int pressed4 = os_dialog(1, \"1-button about dialog\", \"Bla.\\nBla.\");\n\n    const char *buttons[] = { \"no\", \"yes/ok\", \"cancel/error\" };\n    printf(\"User pressed '%s'\\n\", buttons[ pressed1 ] );\n    printf(\"User pressed '%s'\\n\", buttons[ pressed2 ] );\n    printf(\"User pressed '%s'\\n\", buttons[ pressed3 ] );\n    printf(\"User pressed '%s'\\n\", buttons[ pressed4 ] );\n\n    assert( os_dialog(2, \"Warning!\", \"This is a test.\\nIs this dialog visible?\" ) );\n    assert(~puts(\"Ok\") );\n}\n#define main main__\n#endif // DIALOG_DEMO\n#endif // DIALOG_C\n"
  },
  {
    "path": "vault/os_die.c",
    "content": "#ifndef DIE_H\n#define DIE_H\n\n#define os_die(...) os_die(-__LINE__, __VA_ARGS__)\nvoid (os_die)(int rc, const char *fmt, ...);\n\n#endif\n\n#ifdef DIE_C\n#pragma once\n#include <errno.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifdef _WIN32\n#include <windows.h>\n#endif\n\nvoid (os_die)(int rc, const char *fmt, ...) {\n    fflush(stdout);\n    // msg\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    // os\n#ifdef _WIN32\n    if( GetLastError() ) {\n        LPSTR messageBuffer = 0;\n        size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,\n                                     NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);\n\n        char buf[1024+1];\n        size = size < 1024 ? size : 1024;\n        memcpy( buf, messageBuffer, size );\n        buf[size] = 0;\n\n        LocalFree(messageBuffer);\n        fprintf(stderr, \" (%s)\", buf);\n    }\n#endif\n    // crt\n    fprintf(stderr, \" (%s)\\r\\n\", strerror(errno));\n    // bye\n    exit(rc);\n}\n\n#ifdef DIE_DEMO\nint main() {\n    errno = ENOMEM;\n    os_die(\"omg cant believe you\");\n}\n#define main main__\n#endif // DIE_DEMO\n#endif // DIE_C\n"
  },
  {
    "path": "vault/os_entropy.c",
    "content": "// - rlyeh, public domain\n\nvoid os_entropy( void *buf, unsigned n );\n\n\n#ifdef ENTROPY_C\n#pragma once\n\n#ifdef _WIN32\n#include <winsock2.h>\n#include <wincrypt.h>\n#pragma comment(lib, \"advapi32\")\n\nvoid os_entropy_( void *buf, unsigned n ) {\n    HCRYPTPROV provider;\n    if( CryptAcquireContext( &provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == 0 ) {\n        assert(!\"CryptAcquireContext failed\");\n    }\n\n    int rc = CryptGenRandom( provider, n, (BYTE *)buf );\n    assert( rc != 0 );\n    CryptReleaseContext( provider, 0 );\n}\n\n#elif 1\n#include <stdio.h>\n\nvoid os_entropy_( void *buf, unsigned n ) {\n    FILE *fp = fopen( \"/dev/urandom\", \"r\" );\n    if( !fp ) assert(!\"/dev/urandom open failed\");\n\n    size_t read = fread( buf, 1, n, fp );\n    assert( read == n && \"/dev/urandom read failed\" );\n    fclose( fp );\n}\n\n#elif 1 // unused for now\n\n// pseudo random number generator with 128 bit internal state... probably not suited for cryptographical usage.\n// [src] http://github.com/kokke (UNLICENSE)\n// [ref] http://burtleburtle.net/bob/rand/smallprng.html\n\n#include <time.h>\n\n#ifdef _WIN32\n#include <process.h>\n#define getpid _getpid\n#else\n#include <unistd.h>\n#endif\n\nstatic uint32_t prng_next(void) {\n    #define prng_rotate(x,k) (x << k) | (x >> (32 - k))\n    #define prng_shuffle() do { \\\n    uint32_t e = ctx[0] - prng_rotate(ctx[1], 27); \\\n    ctx[0] = ctx[1] ^ prng_rotate(ctx[2], 17); \\\n    ctx[1] = ctx[2] + ctx[3]; \\\n    ctx[2] = ctx[3] + e; \\\n    ctx[3] = e + ctx[0]; } while(0)\n    static __thread uint32_t ctx[4], *once = 0; if( !once ) {\n        uint32_t seed = (uint32_t)( getpid() + time(0) + ((uintptr_t)once) );\n        ctx[0] = 0xf1ea5eed;\n        ctx[1] = ctx[2] = ctx[3] = seed;\n        for (int i = 0; i < 31; ++i) {\n            prng_shuffle();\n        }\n        once = ctx;\n    }\n    prng_shuffle();\n    return ctx[3];\n}\n\nvoid os_entropy_( void *buf, unsigned n ) {\n    for( ; n >= 4 ; n -= 4 ) {\n        uint32_t a = prng_next();\n        memcpy(buf, &a, 4);\n        buf = ((char*)buf) + 4;\n    }\n    if( n > 0 ) {\n        uint32_t a = prng_next();\n        memcpy(buf, &a, n);\n    }\n}\n\n#endif\n\nvoid os_entropy(void *buf, unsigned n) {\n    assert(n <= 2048);\n\n#if 0\n    os_entropy_(buf, n);\n#else\n    // acquire twice, ensure 1st and 2nd parts are different\n    // would this prevent some kind of dummy hijacking?\n    memset(buf, 0, n);\n    os_entropy_(buf, n/2);\n    os_entropy_((char*)buf + n/2, n/2 + n&1);\n    assert(0 != memcmp(buf, (char*)buf + n/2, n/2));\n#endif\n}\n\n\n\n#ifdef ENTROPY_DEMO\nint main() {\n    unsigned char buf[128];\n    os_entropy(buf, 128);\n    for( int i = 0; i < 128; ++i ) {\n        printf(\"%02x\", buf[i]);\n    }\n    puts(\"\");\n}\n#define main __main\n#endif // ENTROPY_DEMO\n#endif // ENTROPY_C\n"
  },
  {
    "path": "vault/os_env.c",
    "content": "#ifndef ENV_H\n#define ENV_H\n\n// environment folders\n\nchar*    env_user(); // user name\nchar*    env_home(); // user home location\nchar*    env_curr(); // current directory\nchar*    env_game(); // binary location\nchar*    env_save(); // save data location\nchar*    env_temp(); // temp data location\nuint64_t env_free(); // available free space\n\n// environment vars\n\nconst char *env_get( const char *key );\nconst char *env_set( const char *key, const char *value );\n\n#endif\n\n// # env ######################################################################\n// @ todo: paths must end with slash always\n\n#ifdef ENV_C\n#pragma once\n#include <stdint.h>\n#include <stdlib.h>\n#ifndef _WIN32\n#include <pwd.h>\n#endif\n\n#ifndef PATH_MAX\n#ifdef MAX_PATH\n#define PATH_MAX MAX_PATH\n#elif defined _MAX_PATH\n#define PATH_MAX _MAX_PATH\n#else\n#define PATH_MAX 260\n#endif\n#endif\n\nstatic char *env_get_process_full_path_() {\n    static char *t = 0;\n    if(t) return t;\n\n    char path[PATH_MAX+1] = {0};\n\n#ifdef __APPLE__ // _IOS || _OSX\n    uint32_t i = sizeof(path);\n    if (_NSGetExecutablePath(path, &i) > -1) {\n        return t = STRDUP(path);\n    }\n#elif defined __linux__ // _LIN\n    //if (readlink(strf(\"/proc/%d/exe\", getpid()), path, sizeof(path)) > -1) {\n    if (readlink(\"/proc/self/exe\", path, sizeof(path)) > -1) {\n        return t = STRDUP(path);\n    }\n#elif defined _WIN32\n    if (GetModuleFileNameA(0, path, sizeof(path))) {\n        return t = STRDUP(path);\n    }\n#endif\n    //t = STRDUP( __argv[0] );\n    //return t = dirabs( &t );\n    return \"./\";\n}\n\n// util that ensure paths end with '/' and are normalized as well.\nstatic char *env_fix_(const char *pathfile ) { // must free() after use\n    char *buf = (char*)MALLOC( PATH_MAX + 1 );\n    strcpy(buf, pathfile);\n    int len = strlen(buf);\n    for( int i = 0; i < len; ++i ) if( buf[i] == '\\\\' ) buf[i] = '/';\n    if( buf[ len ] != '/' ) {\n        buf[ len ] = '/';\n    }\n    return buf;\n}\n\nchar *env_user() {\n    static char *t = 0;\n    if(t) return t;\n    t = t ? t : getenv(\"USER\");\n    t = t ? t : getenv(\"USERNAME\");\n    t = STRDUP( t ? t : \"GUEST\" );\n    return t;\n}\nchar *env_home() {\n    static char *t = 0;\n    if(t) return t;\n    t = t ? t : getenv(\"USERPROFILE\");\n    t = t ? t : getenv(\"HOME\");\n    t = env_fix_( t ? t : \"./\" );\n    return t;\n}\nchar *env_save() { // envdata\n    static char *t = 0;\n    if(t) return t;\n    t = t ? t : getenv(\"APPDATA\");\n    t = t ? t : getenv(\"XDG_DATA_HOME\");\n    t = env_fix_( t ? t : \"./\" );\n    return t;\n}\nchar *env_temp() {\n    static char *t = 0;\n    if(t) return t;\n    t = t ? t : getenv(\"TMPDIR\");\n    t = t ? t : getenv(\"TMP\");\n    t = t ? t : getenv(\"TEMP\");\n#ifdef _WIN32\n    // GetTempPathW(n, buf);\n#else\n    t = t ? t : \"/tmp\";\n#endif\n    t = env_fix_( t ? t : \"./\" );\n    return t;\n}\nstatic __thread char cwd[PATH_MAX+1];\nchar *env_curr() { // envwork\n#ifdef _WIN32\n    _getcwd(cwd, sizeof(cwd));\n#else\n    getcwd(cwd, sizeof(cwd));\n#endif\n    return env_fix_( cwd );\n}\nuint64_t env_free() {\n#ifdef _WIN32\n    DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters;\n    if( GetDiskFreeSpaceA( \".\\\\\", &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters ) ) {\n        return ((uint64_t)NumberOfFreeClusters) * SectorsPerCluster * BytesPerSector;\n    }\n#endif\n    return UINT64_C(-1); // ~0LLU;\n}\n\nchar *env_game() { // envexec, envgame\n    static char *t = 0;\n    if( t ) return t;\n\n    t = STRDUP( env_get_process_full_path_() );\n    for( size_t i = strlen(t); i-- > 0; ) {\n        if (t[i] == '\\\\' || t[i] == '/') {\n            t[i] = '\\0';\n            break;\n        }\n    }\n    return env_fix_(t);\n}\n\n// -----------------------------------------------------------------------------\n\nconst char *env_set( const char *key, const char *value ) { //$\n#ifdef _WIN32\n    char buf[1024];\n    sprintf(buf,\"%s=%s\", key, value ? value : \"\");\n    putenv( buf );\n#else\n    setenv( key, value ? value : \"\", 1 );\n#endif\n    return value;\n}\nconst char *env_get( const char *key ) { //$\n    return getenv(key);\n}\n\n#ifdef ENV_DEMO\n#include <stdio.h>\nint main() {\n    printf(\"env_curr: %s\\n\", env_curr() );\n    printf(\"env_home: %s\\n\", env_home() );\n    printf(\"env_game: %s\\n\", env_game() );\n    printf(\"env_save: %s\\n\", env_save() );\n    printf(\"env_temp: %s\\n\", env_temp() );\n    printf(\"env_user: %s\\n\", env_user() );\n\n    double GiB = 1024 * 1024 * 1024;\n    printf(\"env_free: %.3f GiB\\n\", env_free() / GiB );\n\n    env_set(\"HELLO\", \"WORLD\");\n    assert( 0 == strcmp(env_get(\"HELLO\"), \"WORLD\"));\n    assert(~puts(\"Ok\"));\n}\n#define main main__\n#endif // ENV_DEMO\n#endif // ENV_C\n"
  },
  {
    "path": "vault/os_exec.c",
    "content": "// cmd system invokation\n// - rlyeh, public domain.\n\nchar *os_exec( const char *cmd );\n\n#ifdef EXEC_C\n#pragma once\n#ifdef _WIN32\n#define popen  _popen\n#define pclose _pclose\n#endif\nchar *os_exec( const char *cmd ) {\n    static __thread char buf[4096]; buf[0] = 0;\n    FILE *fp = popen( cmd, \"rt\" );\n    if( fp ) {\n        while( fgets(buf, 4096 - 1, fp) ) {\n            char *r = strrchr(buf, '\\r');\n            char *n = strrchr(buf, '\\n');\n            if( r ) *r = 0;\n            if( n ) *n = 0;\n            //puts(buf);\n        }\n        pclose(fp);\n    }\n    return buf;\n}\n#endif\n"
  },
  {
    "path": "vault/os_exit.c",
    "content": "// - rlyeh, public domain\n\n#ifndef EXIT_H\n#define EXIT_H\n\nvoid os_exit(int rc, const char *msg);\n#define os_exit(rc, ...) os_exit(rc, va(\"Error: \" __VA_ARGS__))\n\n#endif\n\n#ifdef EXIT_C\n#pragma once\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifdef _WIN32\n#include <winsock2.h>\n#endif\n\nvoid (os_exit)(int rc, const char *msg) {\n    fprintf(stderr, \"%s\\n\", msg);\n\n#ifdef _WIN32\n    MessageBoxA(0,msg,0,0);\n#endif\n\n    exit(rc);\n}\n\n#endif\n"
  },
  {
    "path": "vault/os_file.c",
    "content": "// file functions\n// - rlyeh, public domain.\n//\n// @todo: file_lock, file_unlock\n\n#ifndef FILE_H\n#define FILE_H\n#include <stdio.h>\n#include <stdbool.h>\n\nchar*       file_read( const char *pathfile ); // returns temporary data\nbool        file_write( const char *pathfile, const void *data, int len );\nbool        file_append( const char *pathfile, const void *data, int len );\n\nchar*       file_map( const char *pathfile, size_t offset, size_t len );\nvoid        file_unmap( char *buf, size_t len );\nchar*       file_chunk( const char *pathfile, size_t offset, size_t len ); // returns temporary data\n\nint         file_size( const char *pathfile ); // 4gib limit\nint         file_stamp( const char *pathfile ); // Y2038 limit\n\nbool        file_exact( const char *pathfile1, const char *pathfile2 );\nbool        file_exist( const char *pathfile );\nbool        file_isdir( const char *pathfile );\nbool        file_isfile( const char *pathfile );\nbool        file_islink( const char *pathfile );\n\nbool        file_copy( const char *pathsrc, const char *pathdst );\nbool        file_touch( const char *pathfile, size_t modtime ); // can be 0\nbool        file_delete( const char *path );\n\nconst char* file_base( const char *file );\nchar*       file_norm( const char *pathfile ); // returns temporary normalized name\n\n// uint64_t file_checksum( const char *pathfile );\n\n#endif\n\n#ifdef FILE_C\n#pragma once\n#include <time.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/stat.h>  // stat, lstat\n#include <sys/types.h> // mode_t\n#ifdef _WIN32 // _MSC_VER\n#include <sys/utime.h> // utimbuf, also in <utime.h>\n#else\n#include <utime.h>\n#endif\n#ifdef _WIN32\n#include <io.h>\n#else\n#include <unistd.h>\n#endif\n\n#ifdef _WIN32\n#include <fcntl.h> // O_RDONLY(00)\n// mmap() replacement for Windows. Placed into the public domain (Mike Frysinger)\nenum {  PROT_READ = 0x1, PROT_WRITE = 0x2, PROT_EXEC = 0x4,\n        MAP_SHARED = 0x01, MAP_PRIVATE = 0x02, MAP_ANON = 0x20, MAP_ANONYMOUS = MAP_ANON };\n#define MAP_FAILED    ((void *) -1)\nstatic void* mmap(void* start, size_t length, int prot, int flags, int fd, size_t offset) {\n    // Offsets must be a multiple of the system's allocation granularity.  We\n    // guarantee this by making our view size equal to the allocation granularity.\n    static int32_t page_size = -1; if (page_size < 0) {\n        SYSTEM_INFO sysinfo = { 0 };\n        GetSystemInfo(&sysinfo);\n        page_size = sysinfo.dwAllocationGranularity;\n    }\n\n    DWORD flProtect;\n    size_t end = // length + offset; // 0;\n        length & ~(page_size - 1) + page_size\n        + \n        offset & ~(page_size - 1);\n\n    if( !(prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) ) {\n        if( ( fd == -1 &&  (flags & MAP_ANON) && !offset ) ||\n            ( fd != -1 && !(flags & MAP_ANON)            )) {\n                 if( prot & PROT_EXEC  ) flProtect = prot & PROT_READ ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE;\n            else if( prot & PROT_WRITE ) flProtect = PAGE_READWRITE;\n            else                         flProtect = PAGE_READONLY;\n            HANDLE h = CreateFileMapping( fd == -1 ? INVALID_HANDLE_VALUE : (HANDLE)_get_osfhandle(fd),\n                NULL, flProtect, (end >> 31) >> 1, (uint32_t)end, NULL);\n            if( h != NULL ) {\n                DWORD dwDesiredAccess = 0;\n                dwDesiredAccess |= prot & PROT_WRITE ? FILE_MAP_WRITE : FILE_MAP_READ;\n                dwDesiredAccess |= prot & PROT_EXEC ? FILE_MAP_EXECUTE : 0;\n                dwDesiredAccess |= flags & MAP_PRIVATE ? FILE_MAP_COPY : 0;\n#if 0\n                void *ret = MapViewOfFile(h, dwDesiredAccess, (offset >> 31) >> 1, (uint32_t)offset, length);\n#else\n                // hack: avoid ERROR_MAPPED_ALIGNMENT 1132 (0x46C) error\n                // see https://stackoverflow.com/questions/8583449/memory-map-file-offset-low\n                // see https://stackoverflow.com/questions/9889557/mapping-large-files-using-mapviewoffile\n           \n                // alignment\n                size_t offset_page = offset & ~(page_size - 1);\n                size_t read_size = length + (offset - offset_page);\n\n                void *ret = MapViewOfFile(h, dwDesiredAccess, (offset_page >> 31) >> 1, (uint32_t) offset_page, read_size); //ASSERT(ret, \"win32 error %d\", GetLastError());\n                ret = (char*)ret + (offset - offset_page);\n#endif\n                CloseHandle(h); // close the Windows Handle here (we handle the file ourselves with fd)\n                return ret == NULL ? MAP_FAILED : ret;\n            }\n        }\n    }\n    return MAP_FAILED;\n}\nstatic void munmap(void* addr, size_t length) {\n    UnmapViewOfFile(addr);\n}\n#endif\n\n#ifdef _WIN32\n#ifdef __TINYC__\n    #define CP_UTF8 65001\n    int WINAPI MultiByteToWideChar();\n#else\n    #include <winsock2.h>\n#endif\nwchar_t *file_widen(const char *utf8) { // wide strings (windows only)\n    static __thread wchar_t bufs[4][260];\n    static __thread int index = 0;\n\n    int sz = (int)sizeof(bufs[0]);\n    wchar_t *buf = bufs[(++index) % 4];\n\n    int needed = 2 * MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);\n    buf[0] = 0;\n    if( needed < sz ) {\n        MultiByteToWideChar(CP_UTF8, 0, utf8, -1, (void*)buf, needed);\n    }\n    return (wchar_t *)buf;\n}\n#endif\n\n#define open8(path,mode)  IFDEF(WINDOWS, _wopen(file_widen(path))               ,  open(path, mode) )\n#define fopen8(path,mode) IFDEF(WINDOWS, _wfopen(file_widen(path),file_widen(mode)), fopen(path,mode) )\n#define remove8(path)     IFDEF(WINDOWS, _wremove(file_widen(path))             ,  remove(path)     )\n#define rename8(path)     IFDEF(WINDOWS, _wrename(file_widen(path))             ,  rename(path)     )\n#define stat8(path,st)    IFDEF(WINDOWS, _wstat(file_widen(path),st)            ,  stat(path,st)    ) // _stati64()\n#define stat_             IFDEF(WINDOWS, _stat,                                 ,  stat_t           ) // struct _stati64\n\n\n\nchar* file_map( const char *pathfile, size_t offset, size_t len ) {\n    int file = open(pathfile, O_RDONLY);\n    if( file < 0 ) {\n        return 0;\n    }\n    void *ptr = mmap(0, len, PROT_READ, MAP_SHARED/*MAP_PRIVATE*/, file, offset);\n    if( ptr == MAP_FAILED ) {\n        ptr = 0;\n    }\n    close(file); // close file. mapping held until unmapped\n    return (char *)ptr;\n}\nvoid file_unmap( char *buf, size_t len ) {\n    munmap( buf, len );\n}\nchar* file_chunk(const char *pathfile, size_t offset, size_t len) {\n    static __thread int map = 0;\n    static __thread struct maplen { char *map; int len; } maps[16] = {0};\n    char *mem = file_map( pathfile, offset, len );\n    if( mem ) {\n        struct maplen *bl = &maps[ map = ++map & (16-1) ];\n        if( bl->map ) file_unmap( bl->map, bl->len );\n        bl->map = mem;\n        bl->len = len;\n    }\n    return mem;\n}\n\nint file_size( const char *pathfile ) {\n#if 0\n    FILE *fp = fopen(fname, \"rb\");\n    if(!fp) return 0;\n    fseek(fp, 0L, SEEK_END);\n    size_t sz = ftell(fp);\n    fclose(fp);\n    return (int)sz;\n#else\n    struct stat_ st;\n    uint64_t s = stat8(pathfile, &st) < 0 ? 0ULL : (uint64_t)st.st_size;\n    return (int)s;\n#endif\n}\n\nint file_stamp( const char *pathfile ) {\n    struct stat_ st;\n    uint64_t t = stat8(pathfile, &st) < 0 ? 0ULL : (uint64_t)st.st_mtime;\n    return (int)t;\n}\n\nbool file_exist( const char *pathfile ) {\n    struct stat_ st;\n    return stat8(pathfile, &st) < 0 ? 0 : 1;\n    // _WIN: return _access( filename, 0 ) != -1;\n    // else: return access( filename, F_OK ) != -1;\n}\nbool file_isdir( const char *pathfile ) {\n    struct stat_ st;\n    return stat8(pathfile, &st) < 0 ? 0 : S_IFDIR == ( st.st_mode & S_IFMT );\n}\nbool file_isfile( const char *pathfile ) {\n    struct stat_ st;\n    return stat8(pathfile, &st) < 0 ? 0 : S_IFREG == ( st.st_mode & S_IFMT );\n}\nbool file_islink( const char *pathfile ) {\n#ifdef S_IFLNK\n    struct stat_ st;\n    return stat8(pathfile, &st) < 0 ? 0 : S_IFLNK == ( st.st_mode & S_IFMT );\n#else\n    return 0;\n#endif\n}\n\n\nbool file_exact(const char *fname1, const char *fname2) {\n    bool errors = false;\n    for(FILE *in1 = fopen(fname1, \"rb\"); in1; fclose(in1), in1 = 0)\n    for(FILE *in2 = fopen(fname2, \"rb\"); in2; fclose(in2), in2 = 0) {\n        char buffer[64*1024+1] = {0};\n        while( !errors && fread(buffer,1,32*1024,in1)>0 && fread(buffer+32*1024,1,32*1024,in2)>0 ) {\n            errors |= !!memcmp(buffer, buffer+32*1024, 32*1024);\n        }\n        errors |= !!memcmp(buffer, buffer+32*1024, 32*1024);\n    }\n    return !errors;\n}\n\nchar* file_read(const char *pathfile) {\n#if 0\n    size_t sz = file_size(fname);\n    if( !sz ) return 0;\n    FILE *fp = fopen(fname, \"rb\");\n    if(!fp) return 0;\n    char *data = malloc(sz+1); data[sz] = 0;\n    if( fread(data, 1,sz, fp) != sz ) { free(data); fclose(fp); return 0; }\n    fclose(fp);\n    return data;\n#else\n    static __thread char *bufs[16] = {0};\n    static __thread int buf = 0; buf = ++buf & (16-1);\n\n    char **data = &bufs[ buf ];\n    size_t len = file_size(pathfile);\n    FILE *fp = fopen8(pathfile, \"rb\");\n\n    if( fp && len ) {\n        *data = REALLOC(*data, len + 1);\n        len = fread(*data, 1, len, fp); len[*data] = 0;\n        fclose(fp);\n    } else {\n        *data = REALLOC(*data, 8); 0[*data] = 0;\n    }\n\n    return *data;\n#endif\n}\n\n\nbool file_write(const char *pathfile, const void *data, int len) {\n    bool ok = 0;\n    for( FILE *fp = fopen8(pathfile, \"wb\"); fp; fclose(fp), fp = 0) {\n        ok = len == fwrite(data, 1,len, fp);\n    }\n    return ok;\n}\n\nbool file_append(const char *pathfile, const void *data, int len) {\n    bool ok = 0;\n    for( FILE *fp = fopen8(pathfile, \"a+b\"); fp; fclose(fp), fp = 0) {\n        ok = len == fwrite(data, 1,len, fp);\n    }\n    return ok;\n}\n\nbool file_touch( const char *pathfile, size_t modtime ) {\n    struct stat_ st;\n    if( stat8( pathfile, &st ) >= 0 ) {\n        time_t date = modtime ? (time_t)modtime : time(0);\n        struct utimbuf ut;\n        ut.actime = st.st_atime;  /* keep atime unchanged */\n        ut.modtime = date;        /* set mtime to given time */\n        return utime( pathfile, &ut ) == 0;\n    }\n    return false;\n}\n\nbool file_copy( const char *pathsrc, const char *pathdst ) {\n#  ifdef _WIN32 //  _WIN\n    return CopyFileW( file_widen(pathsrc), file_widen(pathdst), FALSE );\n#elif defined __APPLE__ // _OSX\n    return copyfile( pathsrc, pathdst, 0, COPYFILE_DATA )>=0;\n#else\n    bool ok = 0;\n    FILE *in = fopen8( pathsrc, \"rb\" );\n    if( in ) {\n        FILE *out = fopen8( pathdst, \"wb\" );\n        if( out ) {\n            char buf[1024];\n            while( int n = fread( buf, 1, 1024, in ) ){\n                ok = fwrite( buf, 1, n, out ) == n;\n                if( !ok ) break;\n            }\n            fclose( out );\n        }\n        fclose( in );\n    }\n    return ok;\n#endif\n}\n\nbool file_delete( const char *path ) {\n    remove8( path );\n    return !file_exist(path);\n}\n\nchar *file_norm( const char *name ) {\n    static __thread char bufs[4][260]; // 260: PATH_MAX\n    static __thread int index = 0; index = ++index & 3;\n    char *out = bufs[index], *buf = out, c;\n\n    // skip lowercases+digits+underscores+slashes only. anything else is truncated.\n    // remove dupe slashes\n    // remove dupe underlines\n    if( name ) do {\n        /**/ if( *name >= 'a' && *name <= 'z' ) { *out++ = *name; }\n        else if( *name >= 'A' && *name <= 'Z' ) { *out++ = *name - 'A' + 'a'; }\n        else if( *name >= '0' && *name <= '9' ) { *out++ = *name; }\n        else if( *name == '_'                 ) { *out++ = *name; }\n        else if( *name == '/' || *name == '\\\\') { *out++ = '/'; name += strspn(name, \"/\\\\\"); --name; }\n        else if( *name <= ' ' || *name == '.' ) { *out++ = '_'; name += strspn(name, \". \"); --name; }\n    } while( *++name );\n\n    return buf;\n}\n\nconst char *file_base( const char *file ) {\n    const char *end = strlen(file)+file;\n    const char *a = strrchr(file, '/');\n    const char *b = strrchr(file, '\\\\');\n    if( a > b ) return a+1;\n    if( b > a ) return b+1;\n    return file; // end;\n}\n\n#if 0\nuint64_t file_checksum( const char *pathfile ) {\n    void *x = file_read(pathfile); // from scratch memory\n    uint64_t l = file_size(pathfile);\n    uint64_t crc = crc64( 0, x, l );\n    return crc;\n}\n\nbool file_stat( const char *uri, struct stat *out_info ) {\n#ifdef _WIN32\n    // make win32-friendly stat() call (no trailing slashes)\n    char s[4096] = {0};\n    strcpy(s, uri); // strncpy(s, 4096, uri);\n    for( int l = (int)strlen(s); --l >= 0; ) {\n        if( s[l] == '\\\\' || s[l] == '/' ) s[l] = 0;\n    }\n    uri = s;\n#endif\n    return stat( uri, out_info ) == 0;\n}\n#endif\n\n#ifdef FILE_DEMO\n#pragma once\nint main() {\n    char *readbuf = file_chunk(__FILE__, 0, file_size(__FILE__));\n    printf( \"read: %s\\n\", readbuf );\n\n    char *file1 = file_norm(\"There's\\\\\\\\a///Lady/who's  sure   all that \\\"glitters\\\"/is (gold)/file.audio\");\n    char *file2 = file_norm(file1); // renormalize file should be safe\n    puts(file1);\n    puts(file2);\n    assert( !strcmp(file1, file2) );\n    assert( ~puts(\"ok\") );\n}\n#define main main__\n#endif // FILE_DEMO\n#endif // FILE_C\n"
  },
  {
    "path": "vault/os_icon.c",
    "content": "// change window icon.\n// - rlyeh, public domain.\n\nvoid os_icon(const char *pathfile_ico);  // \"\" to restore (win32 only)\n\n// ----------------------------------------------------------------------------\n\n#ifdef ICON_C\n#pragma once\n\n#ifdef _WIN32\nstatic HICON os_load_ico( const char *ico_pathfile ) {\n    HICON hi = (HICON)LoadImageA( // returns a HANDLE so we have to cast to HICON\n        NULL,             // hInstance must be NULL when loading from a file\n        ico_pathfile,     // .ico file name\n        IMAGE_ICON,       // specifies that the file is an icon\n        0,                // width of the image (we'll specify default later on)\n        0,                // height of the image\n        LR_LOADFROMFILE|  // we want to load a file (as opposed to a resource)\n        LR_DEFAULTSIZE|   // default metrics based on the type (IMAGE_ICON, 32x32)\n        LR_SHARED         // let the system release the handle when it's no longer used\n    );\n    return hi;\n}\nvoid os_icon(const char *pathfile_ico) {\n    // set app .ico after window is created\n    HANDLE hIcon = os_load_ico(pathfile_ico);\n    HWND hWndPseudo = (HWND)GetCurrentProcess();\n    HWND hWndWindow = (HWND)GetActiveWindow();\n    HWND hWndConsole = (HWND)GetConsoleWindow();\n    HWND hWnds[] = { hWndWindow, hWndConsole, hWndPseudo };\n    for( int i = 0; i < (sizeof(hWnds)/sizeof(0[hWnds])); ++i) {\n        SendMessage( hWnds[i], (UINT)WM_SETICON, ICON_BIG,   (LPARAM)hIcon );\n        SendMessage( hWnds[i], (UINT)WM_SETICON, ICON_SMALL, (LPARAM)hIcon );\n    }\n}\n#else\nvoid os_icon(const char *) {\n    // @todo : Use https://wiki.libsdl.org/SDL_SetWindowIcon instead\n}\n#endif\n\n#ifdef ICON_DEMO\nint main() {\n    os_icon(\"demo.ico\");\n    window_title(\"demo.ico\");\n    system(\"pause\");\n    os_icon(\"\");\n}\n#define main main__\n#endif // ICON_DEMO\n#endif // ICON_C\n"
  },
  {
    "path": "vault/os_ini.c",
    "content": "// ini+, extended ini format\n// - rlyeh, public domain\n//\n// # spec\n//\n//   ; line comment\n//   [user]             ; map section name (optional)\n//   name=john          ; key and value (mapped here as user.name=john)\n//   +surname=doe jr.   ; sub-key and value (mapped here as user.name.surname=doe jr.)\n//   age=30             ; numbers\n//   color=240          ; key and value \\\n//   color=253          ; key and value |> array: color[0], color[1] and color[2]\n//   color=255          ; key and value /\n//   color=             ; remove key/value(s)\n//   color=white        ; recreate key; color[1] and color[2] no longer exist\n//   []                 ; unmap section\n//   -note=keys may start with symbols (except plus and semicolon)\n//   -note=linefeeds are either \\r, \\n or \\r\\n.\n//   -note=utf8 everywhere.\n//\n\nchar *ini( const char *text );\n\n#ifdef INI_C\n#pragma once\n\n// @todo:\n// evaluate alt api: num_pairs32_t config_parse_ini(const char *ini, char **keys, char **values);\n\nchar *ini( const char *s ) {\n    char *map = 0;\n    int mapcap = 0, maplen = 0;\n    enum { DEL, REM, TAG, KEY, SUB, VAL } fsm = DEL;\n    const char *cut[6] = {0}, *end[6] = {0};\n    while( *s ) {\n        while( *s && (*s == ' ' || *s == '\\t' || *s == '\\r' || *s == '\\n') ) ++s;\n        /**/ if( *s == ';' ) cut[fsm = REM] = ++s;\n        else if( *s == '[' ) cut[fsm = TAG] = ++s;\n        else if( *s == '+' ) cut[fsm = SUB] = ++s;\n        else if( *s == '=' ) cut[fsm = VAL] = ++s;\n        else if( *s > ' ' && *s <= 'z' && *s != ']' ) cut[fsm = KEY] = cut[SUB] = end[SUB] = s;\n        else { if( *s ) ++s; continue; }\n        /**/ if( fsm == REM ) { while(*s && *s != '\\r'&& *s != '\\n') ++s; }\n        else if( fsm == TAG ) { while(*s && *s != '\\r'&& *s != '\\n'&& *s != ']') ++s; end[TAG] = s; }\n        else if( fsm == KEY ) { while(*s && *s >  ' ' && *s <= 'z' && *s != '=') ++s; end[KEY] = s; }\n        else if( fsm == SUB ) { while(*s && *s >  ' ' && *s <= 'z' && *s != '=') ++s; end[SUB] = s; }\n        else if( fsm == VAL ) { while(*s && *s >= ' ' && *s <= 'z' && *s != ';') ++s; end[VAL] = s;\n            while( end[VAL][-1] <= ' ' ) { --end[VAL]; }\n            char buf[256] = {0}, *key = buf;\n            if( end[TAG] - cut[TAG] ) key += sprintf(key, \"%.*s.\", (int)(end[TAG] - cut[TAG]), cut[TAG] );\n            if( end[KEY] - cut[KEY] ) key += sprintf(key,  \"%.*s\", (int)(end[KEY] - cut[KEY]), cut[KEY] );\n            if( end[SUB] - cut[SUB] ) key += sprintf(key, \".%.*s\", (int)(end[SUB] - cut[SUB]), cut[SUB] );\n            int reqlen = (key - buf) + 1 + (end[VAL] - cut[VAL]) + 1 + 1;\n            if( (reqlen + maplen) >= mapcap ) map = REALLOC( map, mapcap += reqlen + 512 );\n            sprintf( map + maplen, \"%.*s%c%.*s%c%c\", (int)(key - buf), buf, 0, (int)(end[VAL] - cut[VAL]), cut[VAL], 0, 0 );\n            maplen += reqlen - 1;\n        }\n    }\n    return map;\n}\n\n#ifdef INI_DEMO\nint main() {\n    char *kv = ini(\n        \"; line comment\\n\"\n        \"[user]             ; map section name (optional)\\n\"\n        \"name=john          ; key and value (mapped here as user.name=john)\\n\"\n        \"+surname=doe jr.   ; sub-key and value (mapped here as user.name.surname=doe jr.)\\n\"\n        \"age=30             ; numbers\\n\"\n        \"color=240          ; key and value \\\\\\n\"\n        \"color=253          ; key and value |> array: color[0], color[1] and color[2]\\n\"\n        \"color=255          ; key and value /\\n\"\n        \"color=             ; remove key/value(s)\\n\"\n        \"color=white        ; recreate key; color[1] and color[2] no longer exist\\n\"\n        \"[]                 ; unmap section\\n\"\n        \"-note=keys may start with symbols (except plus and semicolon)\\n\"\n        \"-note=linefeeds are either \\\\r, \\\\n or \\\\r\\\\n.\\n\"\n        \"-note=utf8 everywhere.\\n\"\n    );\n\n    if( kv ) {\n        for( char *iter = kv; iter[0]; ) {\n            char *key = iter; while( *iter++ );\n            char *val = iter; while( *iter++ );\n            printf(\"'%s' = '%s'\\n\", key, val );\n        }\n        FREE( kv );\n    }\n}\n#define main main__\n#endif // INI_DEMO\n#endif // INI_C\n"
  },
  {
    "path": "vault/os_locale.c",
    "content": "void os_locale(void);\n\n#ifdef LOCALE_C\n#pragma once\n#include <locale.h>\n\nvoid os_locale(void) {\n    // @graphitemaster reported speed boosts at least on Linux\n    setlocale(LC_ALL, \"C\");\n}\n\n#endif\n"
  },
  {
    "path": "vault/os_logger.c",
    "content": "// [x] logger: info, warn, fail, quit. also todo() and fixme()\n// - rlyeh, public domain\n\n// -----------------------------------------------------------------------------\n\n#ifndef LOGGER_H\n#define LOGGER_H\n\n#ifndef LOGLEVEL\n#   define LOGLEVEL 4 // 0(off).. 4(max)\n#endif\n\n#ifdef SHIPPING\n#   undef  LOGLEVEL\n#   define LOGLEVEL 0\n#endif\n\n#if LOGLEVEL <= 0\n#   define LOG(tags, ...) (void)0\n#else\n#   ifdef _MSC_VER\n#   define SHORT_FILE strrchr(\"\\\\\" __FILE__, '\\\\') // todo: test with +1\n#   else\n#   define SHORT_FILE __FILE__\n#   endif\n#   define LOG(tags, ...) (fprintf(stderr,__VA_ARGS__),fprintf(stderr,\" (%s:%d) %s\\n\",SHORT_FILE,__LINE__,#tags))\n#endif\n\n#if LOGLEVEL >= 1\n#   define LOGQUIT(tags, ...)  do { LOG(tags, __VA_ARGS__); exit(-__LINE__); } while(0)\n#else\n#   define LOGQUIT(tags, ...)  exit(-__LINE__)\n#endif\n\n#if LOGLEVEL >= 2\n#   define LOGFAIL LOG\n#else\n#   define LOGFAIL(tags, ...)  (void)0\n#endif\n\n#if LOGLEVEL >= 3\n#   define LOGWARN LOG\n#else\n#   define LOGWARN(tags, ...)  (void)0\n#endif\n\n#if LOGLEVEL >= 4\n#   define LOGINFO LOG\n#else\n#   define LOGINFO(tags, ...)  (void)0\n#endif\n\n// additional log utils\n#define TODO(...)  do { static int todo  = 0; if(!todo ) { ++todo ; LOGINFO(TODO, __VA_ARGS__); } } while(0)\n#define FIXME(...) do { static int fixme = 0; if(!fixme) { ++fixme; LOGINFO(FIXME, __VA_ARGS__); } } while(0)\n\n#endif // LOGGER_H\n"
  },
  {
    "path": "vault/os_logger2.c",
    "content": "#ifndef LOGGER2_H\n#define LOGGER2_H\n#include <stdio.h>\n\n// create logger with given buffer size\nvoid log_create( FILE *fp, int bufsz );\n\n// append line to all registered logs\nint log_puts( const char *msg, ... );\n\n// utils\nchar *log_stamp(void); // -> \"2020-03-17 20.15.41 Tue\"\n\n#endif\n\n#ifdef LOGGER2_C\n#pragma once\n#include <string.h>\n#include <time.h>\n#include <stdarg.h>\n\nstatic FILE *loggers[32] = {0};\n\nchar *log_stamp(void) {\n    static __thread char date[64];\n    time_t rawtime; time( &rawtime );\n    struct tm *ti = localtime( &rawtime );\n    sprintf(date, \"%04d-%02d-%02d %02d.%02d.%02d %.3s\",\n        1900 + ti->tm_year,\n        ti->tm_mon + 1, \n        ti->tm_mday,\n        ti->tm_hour, ti->tm_min, ti->tm_sec,\n        \"SunMonTueWedThuFriSat\"+3*ti->tm_wday\n    );\n    return date;\n}\n\nvoid log_create( FILE *fp, int bufsz ) {\n    // append logger for broadcasting\n    for( int i = 0; i < 32; ++i) {\n        if( !loggers[i] ) { loggers[i] = fp; break; }\n    }\n    // write header\n    fprintf(fp, \"--\"\"- New session [built %s %s]\\n\", __DATE__, __TIME__);\n    fflush(fp);\n    // release builds might flush logs every 16KiB; any other build could flush every line\n    setvbuf(fp, NULL, _IOFBF, bufsz > 2 ? bufsz : 2);\n    fprintf(fp, \"%s\\n\", log_stamp());\n}\n\nint log_puts( const char *msg, ... ) {\n    va_list vl;\n    va_start(vl, msg);\n    for( int i = 0; i < 32; ++i ) {\n        FILE *fp = loggers[i];\n        if( !fp ) break;\n        vfprintf(fp, msg, vl);\n        fprintf(fp, \"\\n\");\n    }\n    va_end(vl);\n    return !feof(stdout);\n}\n\n#ifdef LOGGER2_DEMO\nint main() {\n    char logname[128]; sprintf(logname, \"log %s.txt\", log_stamp());\n\n    log_create( stdout, 16384 );\n    log_create( fopen(logname,\"a+b\"), 16384 ); // append mode\n    log_create( fopen(\"log-latest.txt\",\"w+b\"), 16384 ); // create\n\n    log_puts(\"hello %d\", 123);\n    log_puts(\"hello %s\", log_stamp());\n}\n#define main __main\n#endif // LOGGER_DEMO\n#endif // LOGGER_C\n"
  },
  {
    "path": "vault/os_logger3.c",
    "content": "// simple logger. likely slow, though.\n// - rlyeh, public domain.\n//\n// - [x] colors based on content.\n// - [x] no logging categories. throughput flood configurable by percentage (see LOG_LEVEL var).\n// - [x] print fatal errors always. with optional callstack (see LOG_PRINT_STACK macro).\n\n#pragma once\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#  if !defined LOG_LEVEL && (defined NDEBUG || defined SHIPPING)\n#define LOG_LEVEL 0   //   0% - no messages logged (only fatal errors will)\n#elif !defined LOG_LEVEL\n#define LOG_LEVEL 100 // 100% - all messages logged\n#endif\n\n#ifndef LOG_TIMER\n#define LOG_TIMER() 0.0 /* user-defined apptime clock here */\n#endif\n\n#ifndef LOG_PRINT_STACK\n#define LOG_PRINT_STACK(f) ftrace(f,+16) /* user-defined callstack printer here */\n#endif\n\n#  if !defined LOG_ENABLE_ANSI && defined _WIN32\n// #include <winsock2.h>\n#define LOG_ENABLE_ANSI() os_ansi() // for(unsigned mode=0;!mode;mode=1) SetConsoleMode(GetStdHandle(-11), (GetConsoleMode(GetStdHandle(-11), &mode), mode|4))\n#elif !defined LOG_ENABLE_ANSI\n#define LOG_ENABLE_ANSI()\n#endif\n\n#ifdef _MSC_VER\n#define LOG_DIRCHR \"\\\\\"\n#else\n#define LOG_DIRCHR \"/\"\n#endif\n\n#define LOGCOL(...) do { \\\n    static char must_log = -1; \\\n    static enum { undefined=-1, restore=0, r=31,g,y,b,p,t,w,inv=0x80 } color = undefined; \\\n    char buf[2048]; snprintf(buf, 2048, \"\" __VA_ARGS__); \\\n    if( color == undefined ) { \\\n        LOG_ENABLE_ANSI(); \\\n        char low[2048]; int i; for(i=0;buf[i];++i) low[i] = 32|buf[i]; low[i]='\\0'; \\\n        /**/ if( strstr(low,\"fatal\")|| strstr(low,\"panic\") || strstr(low,\"assert\") ) color=r|inv,must_log=1; \\\n        else if( strstr(low,\"fail\") || strstr(low,\"error\") ) color=r; \\\n        else if( strstr(low,\"warn\") || strstr(low,\"alert\") ) color=y; /*beware,caution*/ \\\n        else if( strstr(low,\"info\") || strstr(low,\"succe\") ) color=g; /*ok, no error*/ \\\n        else if( strstr(low,\"debug\") ) color=t; \\\n        else if( strstr(low,\"trace\") ) color=p; else color=restore; \\\n        if( must_log < 0 ) { /* original splitmix64 by Sebastiano Vigna (CC0)*/ \\\n            uint64_t z = (__LINE__ + __COUNTER__ + UINT64_C(0x9E3779B97F4A7C15)); \\\n            z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); \\\n            must_log = (unsigned)((z ^ (z >> 31)) % 100) < LOG_LEVEL; } } \\\n    if( must_log ) { \\\n        double timer = LOG_TIMER(); \\\n        const char *short_file = strrchr(LOG_DIRCHR __FILE__, 0[LOG_DIRCHR]) + 1; \\\n        if(color&0x80) fprintf(stderr, \"\\033[7m\"); \\\n        if(timer>0)fprintf(stderr, \"\\033[%dm%07.3fs %s (%s:%d)\", color&0x7f, timer, &buf[buf[0]=='!'], short_file, __LINE__); \\\n        else       fprintf(stderr, \"\\033[%dm%s (%s:%d)\", color&0x7f, &buf[buf[0]=='!'], short_file, __LINE__); \\\n        fprintf(stderr, \"\\033[%dm\\n\", restore); \\\n        if(color&inv || buf[0] == '!') LOG_PRINT_STACK(stderr); \\\n        log_puts(buf); /* <-- optional, only if logger2 is included */ } \\\n} while(0)\n\n#ifdef LOGGER3_C\n#pragma once\n#ifdef LOGGER3_DEMO\nint main() {\n    LOGCOL(\"Test 1 - normal message. lines starting with '!' will print %s\", \"callstack\");\n    LOGCOL(\"Test 2 - trace message\");\n    LOGCOL(\"Test 3 - debug message\");\n    LOGCOL(\"Test 4 - info message\");\n    LOGCOL(\"Test 5 - warning message\");\n    LOGCOL(\"Test 6 - error message\");\n    LOGCOL(\"Test 7 - fatal error message (fatal errors are always printed, despite LOG_LEVEL var)\");\n}\n#define main main__\n#endif // LOGGER3_DEMO\n#endif // LOGGER3_C\n"
  },
  {
    "path": "vault/os_memory.c",
    "content": "// - rlyeh, public domain\n\n#ifndef MEMORY_H\n#define MEMORY_H\n\n#include <string.h>\n#include <stdlib.h>\n\n#ifndef REALLOC\n#define REALLOC        realloc\n#endif\n\n#define MALLOC(n)      REALLOC(0, n)\n#define FREE(p)        REALLOC(p, 0)\n#define CALLOC(c, n)   memset(MALLOC((c)*(n)), 0, (c)*(n))\n#define STRDUP(s)      strcpy(MALLOC(strlen(s)+1), (s))\n\n#ifndef MSIZE\n#   if defined _OSX || defined _BSD\n#       define MSIZE malloc_size\n#   elif defined _AND\n#       define MSIZE dlmalloc_usable_size\n#   elif defined _WIN\n#       define MSIZE _msize\n#   else\n#       define MSIZE malloc_usable_size // glibc\n#   endif\n#endif\n\n#endif\n"
  },
  {
    "path": "vault/os_mime.c",
    "content": "// detect file/mime types\n// - rlyeh, public domain.\n\nconst char *os_mime(const char *filename);\nconst char *os_mime_buf(const char *buf, int len);\n\n#ifdef MIME_C\n#pragma once\n#include <string.h>\n\nconst char *os_mime_buf(const char *buf, int len) {\n    const struct type {\n        int len; const char *ext; const char *buf; int off;\n    } types[] = { //// Descending priority order\n       21, \"deb\", \"!<arch>\\x0a\"\"debian-binary\", 0,\n       20, \"xpi\", \"META-INF/mozilla.rsa\", 30,\n       14, \"mxf\", \"\\x06\\x0e+4\\x02\\x05\\x01\\x01\\x0d\\x01\\x02\\x01\\x01\\x02\", 0,\n       11, \"hdr\", \"#?RADIANCE\\x0a\", 0,\n       11, \"m4v\", \"\\x00\\x00\\x00\\x1c\"\"ftypM4V\", 0, // before mp4\n       10, \"wmv\", \"0&\\xb\"\"2u\"\"\\x8e\"\"f\"\"\\xcf\\x11\\xa6\\xd9\", 0,\n        8, \"mkv\", \"matroska\", 31,\n        8, \"mov\", \"\\x00\\x00\\x00\\x14\"\"ftyp\", 0,\n        8, \"msi\", \"\\xd0\\xcf\\x11\\xe0\\xa1\\xb1\\x1a\\xe1\", 0,\n        8, \"opus\", \"OpusHead\", 28, // before ogg\n        8, \"wav\", \"RIFFWAVE\", 0,\n        8, \"woff\", \"wOFF\\x00\\x01\\x00\\x00\", 0,\n        8, \"woff\", \"wOFFOTTO\", 0,\n        8, \"woff2\", \"wOF2\\x00\\x01\\x00\\x00\", 0,\n        8, \"woff2\", \"wOF2OTTO\", 0,\n        7, \"ar\", \"!<arch>\", 0,\n        7, \"avi\", \"RIFFAVI\", 0,\n        7, \"hdr\", \"#?RGBE\\x0a\", 0,\n        7, \"m4a\", \"ftypM4A\", 4,\n        7, \"rar\", \"Rar!\\x1a\\x07\\x00\", 0,\n        7, \"rar\", \"Rar!\\x1a\\x07\\x01\", 0,\n        6, \"7z\", \"7z\\xbc\\xaf'\\x1c\", 0,\n        6, \"amr\", \"#!AMR\\x0a\", 0,\n        6, \"xz\", \"\\xfd\"\"7zXZ\\x00\", 0,\n        5, \"amr\", \"#!AMR\", 0,\n        5, \"otf\", \"OTTO\\x00\", 0,\n        5, \"rtf\", \"{\\rtf\", 0,\n        5, \"rtf\", \"{\\x0dtf\\x00\", 0,\n        5, \"tar\", \"ustar\", 257,\n        5, \"ttf\", \"\\x00\\x01\\x00\\x00\\x00\", 0,\n        4, \"cab\", \"ISc(\", 0,\n        4, \"cab\", \"MSCF\", 0,\n        4, \"crx\", \"Cr24\", 0,\n        4, \"exr\", \"v/1\\x01\", 0,\n        4, \"flac\", \"fLaC\", 0,\n        4, \"flif\", \"FLIF\", 0,\n        4, \"flv\", \"FLV\\x01\", 0,\n        4, \"ico\", \"\\x00\\x00\\x01\\x00\", 0,\n        4, \"lz\", \"LZIP\", 0,\n        4, \"m4a\", \"M4A \", 0,\n        4, \"mid\", \"MThd\", 0,\n        4, \"mkv\", \"\\x1a\"\"E\"\"\\xdf\\xa3\", 0,\n        4, \"mp4\", \"\\x00\\x00\\x00\\x1c\", 0,\n        4, \"mp4\", \"3gp5\", 0,\n        4, \"mp4\", \"ftyp\", 4,\n        4, \"mpg\", \"\\x00\\x00\\x01b\", 0,\n        4, \"nes\", \"NES\\x1a\", 0,\n        4, \"ogg\", \"OggS\", 0,\n        4, \"otf\", \"OTTO\", 0,\n        4, \"pdf\", \"%PDF\", 0,\n        4, \"png\", \"\\x89PNG\", 0,\n        4, \"psd\", \"8BPS\", 0,\n        4, \"rar\", \"Rar!\", 0,\n        4, \"rpm\", \"\\xed\\xab\\xee\\xdb\", 0,\n        4, \"sqlite\", \"SQLi\", 0,\n        4, \"svg\", \"<svg\", 0,\n        4, \"tif\", \"II*\\x00\", 0,\n        4, \"tif\", \"MM\\x00*\", 0,\n        4, \"tiff\", \"II*\\x00\", 0,\n        4, \"tiff\", \"MM\\x00*\", 0,\n        4, \"wav\", \"WAVE\", 8,\n        4, \"webm\", \"\\x1a\"\"E\"\"\\xdf\\xa3\", 0,\n        4, \"webp\", \"WEBP\", 8,\n        4, \"woff\", \"wOFF\", 0,\n        4, \"woff2\", \"wOF2\", 0,\n        3, \"avi\", \"AVI\", 8,\n        3, \"bz2\", \"BZh\", 0,\n        3, \"eot\", \"\\x00\\x00\\x01\", 8,\n        3, \"eot\", \"\\x01\\x00\\x02\", 8,\n        3, \"eot\", \"\\x02\\x00\\x02\", 8,\n        3, \"gif\", \"GIF\", 0,\n        3, \"gz\", \"\\x1f\\x8b\\x08\", 0,\n        3, \"jpg\", \"\\xff\\xd8\\xff\", 0,\n        3, \"jxr\", \"II\\xbc\", 0,\n        3, \"mp3\", \"ID3\", 0,\n        3, \"mpg\", \"\\x00\\x00\\x01\", 0,\n        3, \"swf\", \"CWS\", 0,\n        3, \"swf\", \"FWS\", 0,\n        2, \"bmp\", \"BM\", 0,\n        2, \"dmg\", \"x\\x01\", 0,\n        2, \"exe\", \"MZ\", 0,\n        2, \"mp3\", \"\\xff\\xfb\", 0,\n        2, \"ps\", \"%!\", 0,\n        2, \"sh\", \"#/-\", 0,\n        2, \"swf\", \"WS\", 1,\n        2, \"z\", \"\\x1f\\x9d\", 0,\n        2, \"z\", \"\\x1f\\xa0\", 0,\n        2, \"zip\", \"PK\", 0,\n        1, \"json\", \"[\", 0, // @todo: improve this weak detection someday.\n        1, \"json\", \"{\", 0, // @todo: improve this weak detection someday.\n        1, \"xml\", \"<\", 0,  // @todo: improve this weak detection someday.\n        0\n    };\n    for( int i = 0; types[i].ext; ++i ) {\n        if( (types[i].off + types[i].len) < len ) {\n            if( 0 == memcmp( buf + types[i].off, types[i].buf, types[i].len ) ) {\n                return types[i].ext;\n            }\n        }\n    }\n    return \"\";\n}\n\nconst char *os_mime(const char *fname) {\n    const char *ftype = \"\";\n    // examine contents...\n    for( FILE *fp = fopen(fname, \"rb\" ); fp; fclose(fp), fp = 0) {\n        char buf[512];\n        int len = fread(buf, 1, 512, fp);\n        ftype = os_mime_buf(buf, len);\n    }\n    // else use extension as detection\n    if( !ftype[0] ) {\n        ftype = strrchr(fname, '.');\n        ftype += !!ftype;\n    }\n    return ftype;\n}\n\n#endif\n\n#ifdef MIME_DEMO\n#include <stdio.h>\nint main( int argc, const char **argv ) {\n    if( argc == 2 ) {\n        puts( os_mime(argv[1]) );\n        exit(0);\n    }\n    // samples taken from https://github.com/mathiasbynens/small\n    const unsigned char unknown1[] = {\n        0x3C,0x3F,0x78,0x6D,0x6C,0x20,0x76,0x65,0x72,0x73,0x69,0x6F,0x6E,0x3D,0x22,0x31,\n        0x2E,0x31,0x22,0x3F,0x3E,0x3C,0x5F,0x2F,0x3E\n    };\n    const unsigned char unknown2[] = {\n        0x47,0x49,0x46,0x38,0x39,0x61,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x3B\n    };\n    const unsigned char unknown3[] = {\n        0x42,0x4D,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1A,0x00,0x00,0x00,0x0C,0x00,\n        0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x18,0x00,0x00,0x00,0xFF,0x00\n    };\n    const unsigned char unknown4[] = {\n        0x50,0x4B,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\n        0x00,0x00,0x00,0x00,0x00,0x00\n    };\n    const unsigned char unknown5[] = {\n        0x7B,0x5C,0x72,0x74,0x66,0x31,0x7D\n    };\n    const unsigned char unknown6[] = {\n        0x52,0x49,0x46,0x46,0x12,0x00,0x00,0x00,0x57,0x45,0x42,0x50,0x56,0x50,0x38,0x4C,\n        0x06,0x00,0x00,0x00,0x2F,0x41,0x6C,0x6F,0x00,0x6B\n    };\n    puts( os_mime_buf( unknown1, sizeof(unknown1) ) );\n    puts( os_mime_buf( unknown2, sizeof(unknown2) ) );\n    puts( os_mime_buf( unknown3, sizeof(unknown3) ) );\n    puts( os_mime_buf( unknown4, sizeof(unknown4) ) );\n    puts( os_mime_buf( unknown5, sizeof(unknown5) ) );\n    puts( os_mime_buf( unknown6, sizeof(unknown6) ) );\n}\n#endif\n"
  },
  {
    "path": "vault/os_singleton.c",
    "content": "// - rlyeh, public domain\n\nbool os_singleton(const char *guid);\n\n#ifdef SINGLETON_C\n#pragma once\n#include <stdbool.h>\n\n#ifdef _WIN32\n    // from microsoft website\n\n    //#include <winsock2.h>\n    #include <stdlib.h>\n    #include <stdio.h>\n\n    static HANDLE app_mutex  = 0;\n\n    void os_singleton__quit(void) {\n        if( app_mutex ) {\n            ReleaseMutex( app_mutex );\n            app_mutex  = NULL;\n        }\n    }\n\n    bool os_singleton(const char *guid) {\n        //Make sure that you use a name that is unique for this application otherwise\n        //two apps may think they are the same and it wont work.\n        char buffer[128];\n        sprintf(buffer, \"Global\\\\{%s}\", guid);\n        app_mutex  = CreateMutexA(NULL, FALSE, buffer);\n        if(ERROR_ALREADY_EXISTS == GetLastError()) {\n            return false;\n        }\n        atexit(os_singleton__quit); // needed?\n        return true;\n    }\n\n#else\n\n    bool os_singleton(const char *guid) {\n        return true;\n    }\n\n#endif\n\n#ifdef SINGLETON_DEMO\n#include <stdio.h>\nint main() {\n    bool ok = os_singleton(\"619967F0-CDD6-48b5-9C61-DE91175C3112\");\n    if( ok ) {\n        puts(\"Ok. os_singleton() initialized...\");\n    } else {\n        puts(\"Error: App already initialized...\");\n    }\n    system(\"pause\");\n}\n#define main main__\n#endif // SINGLETON_DEMO\n#endif // SINGLETON_C\n"
  },
  {
    "path": "vault/os_test.c",
    "content": "// # tst ######################################################################\n// @todo: measure time with overrides as well, so it works as benchmark.\n// double (*benchmark)() = 0;\n// unit() { now = benchmark(); }\n// test() { ... }\n\nint unit(const char *name);\nint test(int expr);\n\n#ifdef TEST_C\n#pragma once\n#include <stdio.h>\n\nstatic __thread int right = 0, wrong = 0;\nstatic __thread const char *suite = \"\";\n\nint unit(const char *name) {\n    suite = name;\n    right = wrong = 0;\n    return 1;\n}\nint test(int expr) {\n    right = right + !!expr;\n    wrong = wrong +  !expr;\n\n    char buffer[1024];\n    sprintf(buffer, \"%s%c Unit '%s': test %d/%d %s\", // (%5.2f%%)\",\n        !expr ? \"!\" : \"\",\n        \"NY\"[expr && !wrong],\n        suite,\n        right, right+wrong,\n        !expr ? \"FAILED\" : \"passed\"\n        //,100.f * right / (right+wrong)\n    );\n\n#if 1\n    fprintf(stderr, \"%s\\n\", buffer[0] == '!' ? buffer+1 : buffer);\n    fflush(stderr);\n#else\n    LOG(TEST, \"%s\", buffer);\n#endif\n\n    return !!expr;\n}\n\n#ifdef TEST_DEMO\nint main() {\n    if( unit( \"1st unit\" ) ) {\n        test( 1 < 4 );\n        test( 2 < 4 );\n        test( 3 < 4 );\n    }\n    if( unit( \"2nd unit\") ) {\n        test( 10 < 10 ); // <-- shall fail here\n    }\n    if( unit( \"3rd unit\" ) ) {\n        test( 1 < 2 );\n    }\n}\n#define main main__ \n#endif // TEST_DEMO\n#endif // TEST_C\n"
  },
  {
    "path": "vault/os_trap.c",
    "content": "void os_trap( void(*handler)(int) );\nvoid os_crash(void);\n\n\n#ifdef TRAP_C\n#pragma once\n#include <float.h> // _control87\n#include <signal.h>\n#include <stdio.h>\nvoid (*os_signal)(int);\nvoid os_signal_(int handler) {\n    // reload signal\n    // signal(handler, os_signal_);\n    // report\n    if( os_signal ) {\n        os_signal(handler);\n    } else {\n        const char *signame = \"?\";\n        /**/ if( handler == SIGABRT ) signame = \"SIGABRT\";\n        else if( handler == SIGFPE )  signame = \"SIGFPE\";\n        else if( handler == SIGILL )  signame = \"SIGILL\";\n        else if( handler == SIGINT )  signame = \"SIGINT\";\n        else if( handler == SIGSEGV ) signame = \"SIGSEGV\";\n        else if( handler == SIGTERM ) signame = \"SIGTERM\";\n        // panic(\"!exception caught, signal: %s (%d)\\n\", signame, handler);\n        fprintf(stderr, \"exception caught, signal: %s (%d)\\n\", signame, handler);\n        exit(-1);\n    }\n}\nvoid os_trap( void(*handler)(int) ) {\n#ifdef _MSC_VER\n    _control87(0, _MCW_EM);      // Unmask all FPE\n#endif\n    signal(SIGABRT, os_signal_); // Abnormal termination\n    signal(SIGFPE, os_signal_);  // Floating-point error\n    signal(SIGILL, os_signal_);  // Illegal instruction\n    signal(SIGINT, os_signal_);  // CTRL+C signal\n    signal(SIGSEGV, os_signal_); // Illegal storage access\n    signal(SIGTERM, os_signal_); // Termination request\n    os_signal = handler;\n}\n\nvoid os_crash(void) {\n    int *p = 0;\n    *p = 42;\n}\n\n#ifdef TRAP_DEMO\nint main() {\n    os_trap(NULL);\n\n    printf(\"signal? [1..6]: \");\n    int test;\n    if( scanf(\"%d\", &test) ) {\n        if( test == 1 ) { abort(); } // test SIGABRT\n        if( test == 2 ) { float a = 0; printf(\"%f\\n\", 10/a); } // test SIGFPE\n        if( test == 3 ) { raise(SIGILL); } // test SIGILL\n        if( test == 4 ) { puts(\"ctrl-c to signal\"); for(;;) {} } // test SIGINT\n        if( test == 5 ) { char *p = 0; *p = 42; } // test SIGSEGV\n        if( test == 6 ) { raise(SIGTERM); } // test SIGTERM\n    }\n}\n#define main main__\n#endif // TRAP_DEMO\n#endif // TRAP_C\n\n\n#if 0\n\nvoid os_crash(void);\nvoid os_trap(void);\n\n#ifdef TRAP_C\n#pragma once\n\n#include <signal.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <signal.h>\n\n#ifndef _WIN32\n#include <sys/resource.h> // setrlimit()\n#else\n#include <winsock2.h>\n#endif\n\nstatic void catch_signal( int sig ) {\n    signal(sig, catch_signal); // reset for next signal\n\n    /**/ if(sig == SIGTERM) panic(\"!catch_signal(SIGTERM): A termination request was sent to the program\");\n    else if(sig == SIGABRT) panic(\"!catch_signal(SIGABRT): Usually caused by an abort() or assert()\");\n    else if(sig == SIGSEGV) panic(\"!catch_signal(SIGSEGV): Segmentation Fault\");\n    else if(sig == SIGINT ) panic(\"!catch_signal(SIGINT): Interactive attention signal (usually ctrl+c)\");\n    else if(sig == SIGFPE ) panic(\"!catch_signal(SIGFPE): Arithmetic Exception\");\n    else if(sig == SIGILL ) panic(\"!catch_signal(SIGILL): Illegal Instruction\");\n    else                    panic(\"!catch_signal(): Unknown exception caught.\");\n}\n\n#if defined _MSC_VER && defined __cplusplus\n#   include <winsock2.h> // windows.h alternative\n#   include <eh.h>       // _set_se_translator\nstatic void _cdecl catch_se( unsigned int ex, EXCEPTION_POINTERS *p ) {\n    /**/ if(ex == EXCEPTION_ACCESS_VIOLATION)    panic(\"!catch_se(EXCEPTION_ACCESS_VIOLATION): Memory access violation\");\n    else if(ex == EXCEPTION_ILLEGAL_INSTRUCTION) panic(\"!catch_se(EXCEPTION_ILLEGAL_INSTRUCTION): Illegal instruction\");\n    else if(ex == EXCEPTION_INT_DIVIDE_BY_ZERO)  panic(\"!catch_se(EXCEPTION_INT_DIVIDE_BY_ZERO): Integer divide by zero\");\n    else if(ex == EXCEPTION_STACK_OVERFLOW)      panic(\"!catch_se(EXCEPTION_STACK_OVERFLOW): Stack overflow\");\n    else                                         panic(\"!catch_se(): Unknown exception\");\n}\n#endif\n\n#if 0 // ndef __TINYC__\n#include <fenv.h>\n#ifdef _MSC_VER\n#pragma fenv_access(on)\n#else\n#pragma STDC FENV_ACCESS ON\n#endif\nvoid os_trap_fpe() {\n    // ignore fp exceptions\n    static fenv_t fenv = {0};\n    feholdexcept( &fenv );\n    // config fp rounding mode to chop (round towards zero); easier to emulate in software than round-to-nearest.\n    fesetround(FE_TOWARDZERO);\n}\n#endif\n\nvoid os_trap(void) { // @todo: TRAP_C, TRAP_CPP, TRAP_FPE flags?\n    // install signal handlers\n    const int signals[] = {\n    // The C standard defines following 6 signals:\n        SIGABRT,      // abort; abnormal termination.\n        SIGFPE,       // floating point exception.\n        SIGILL,       // illegal; invalid instruction.\n        SIGSEGV,      // segmentation violation; invalid memory access.\n        SIGTERM,      // terminate; termination request sent to the program.\n//      SIGINT,       // interrupt; interactive attention request sent to the program. SHIPPING ONLY?\n    // OS specifics:\n    #ifdef __APPLE__ // _OSX || _IOS\n        SIGPIPE,\n    #endif\n    #ifdef _WIN32\n        SIGBREAK,\n    #else\n        SIGBUS,       // Bus error\n        SIGHUP,       // sent to a process when its controlling terminal is closed\n        //SIGQUIT,    //\n        //SIGKILL,    // kernel will let go of the process without informing the process of it\n        //SIGTRAP,    // debugger\n        //SIGSYS,\n    #endif\n    };\n    for( int i = 0; i < sizeof(signals)/sizeof(signals[0]); ++i ) {\n        //signal(signals[i], SIG_IGN); //catch_signal);\n        if (signal(signals[i], catch_signal) == SIG_ERR) {\n            panic(\"!An error occurred while setting a signal handler.\");\n        }\n    }\n#ifdef __cplusplus\n    set_terminate(catch_signal); // C++11\n    #ifdef _MSC_VER // _WIN32\n    _set_se_translator(catch_se);\n    #endif\n#endif\n#if 0 // ndef _WIN32\n    // enable coredumps\n    rlimit core_limit = { RLIM_INFINITY, RLIM_INFINITY };\n    setrlimit( RLIMIT_CORE, &core_limit );\n#endif\n#if 0 // ndef _WIN32\n    // daemon + unstopable + no zombies children (= no wait())\n    #ifndef SIGCLD\n    #define SIGCLD SIGCHLD\n    #endif\n    signal(SIGCLD, SIG_IGN); // ignore child death\n    signal(SIGHUP, SIG_IGN); // ignore terminal hangups\n    setpgrp();               // break away from process group\n#endif\n}\n\nvoid os_crash(void) {\n    int *p = 0;\n    *p = 42;\n}\n\n\n#ifdef TRAP_DEMO\nint main() {\n    os_trap();\n    os_crash();\n}\n#define main main__\n#endif // TRAP_DEMO\n#endif // TRAP_C\n\n#endif\n"
  },
  {
    "path": "vault/os_tray.c",
    "content": "// Based on code from MinimalSystray project (unlicensed)\n// - rlyeh, public domain.\n\nvoid os_tray( const char *tray_name, const char *tray_icon_pathfile );\n\n// ----------------------------------------------------------------------------\n\n#ifdef TRAY_C\n#pragma once\n\n#if defined _WIN32 //&& !defined __TINYC__\n#include <windows.h>\n#include <shellapi.h>\n#pragma comment(lib, \"user32\")\n#pragma comment(lib, \"shell32\")\nstatic volatile HWND tray_window = 0;\nstatic const char *TRAY_ICON_PATHFILE = 0;\nstatic const char *TRAY_NAME = \"\";\nstatic LRESULT CALLBACK SystrayThreadProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {\n    //printf(\"debug msg %d\\n\", Msg);\n    enum EButtons { IDM_NONE, IDM_EXIT };\n    static UINT s_WM_TASKBARRESTART;\n    if (Msg == WM_COMMAND && wParam == IDM_EXIT) { NOTIFYICONDATAA i; ZeroMemory(&i, sizeof(i)); i.cbSize = sizeof(i); i.hWnd = hWnd; Shell_NotifyIconA(NIM_DELETE, &i); ExitProcess(0); }\n    if (Msg == WM_USER && (LOWORD(lParam) == WM_LBUTTONUP || LOWORD(lParam) == WM_RBUTTONUP)) {\n        HMENU hPopMenu = CreatePopupMenu();\n        InsertMenuA(hPopMenu,0xFFFFFFFF,MF_STRING|MF_GRAYED,IDM_NONE, TRAY_NAME);\n        InsertMenuA(hPopMenu,0xFFFFFFFF,MF_SEPARATOR,IDM_NONE,NULL);\n        InsertMenuA(hPopMenu,0xFFFFFFFF,MF_STRING,IDM_EXIT,\"Exit\");\n        SetForegroundWindow(hWnd); //cause the popup to be focused\n        POINT lpClickPoint;\n        GetCursorPos(&lpClickPoint);\n        TrackPopupMenu(hPopMenu,TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_BOTTOMALIGN, lpClickPoint.x, lpClickPoint.y,0,hWnd,NULL);\n    }\n    if (Msg == WM_CREATE || Msg == s_WM_TASKBARRESTART) {\n        if (Msg == WM_CREATE) s_WM_TASKBARRESTART = RegisterWindowMessageA(TRAY_NAME);\n        NOTIFYICONDATAA nid;\n        ZeroMemory(&nid, sizeof(nid));\n        nid.cbSize = sizeof(nid); \n        nid.hWnd = hWnd;\n        nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; \n        nid.hIcon = 0;\n        if( TRAY_ICON_PATHFILE ) {\n            nid.hIcon = os_load_ico(TRAY_ICON_PATHFILE);\n        } else {\n            //GetIconFromParentProcess();\n            //GetIconFromDLL( \"imageres.dll\", 19 );\n            //LoadIconA(GetModuleHandleA(NULL), \"ICN\");\n            //etc; \n        }\n        nid.uCallbackMessage = WM_USER; \n        snprintf(nid.szTip, sizeof(nid.szTip), \"%s\", TRAY_NAME);\n        Shell_NotifyIconA(NIM_ADD, &nid);\n    }\n    return DefWindowProcA(hWnd, Msg, wParam, lParam);\n}\nstatic DWORD CALLBACK SystrayThread(LPVOID arg) {\n    MSG Msg;\n    WNDCLASSA c;\n    ZeroMemory(&c, sizeof(c));\n    c.lpfnWndProc = SystrayThreadProc;\n    c.hInstance = GetModuleHandleA(NULL);\n    c.lpszClassName = TRAY_NAME;\n    if (!RegisterClassA(&c)) return 1;\n    tray_window = CreateWindowA(c.lpszClassName, 0, 0, 0, 0, 0, 0, 0, 0, c.hInstance, 0);\n    if( !tray_window ) return 1;\n    while (GetMessageA(&Msg, 0, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessageA(&Msg); }\n    tray_window = 0;\n    return 0;\n}\n// install a systray icon that:\n// - uses __argv[0]+.ico\n// - has context popup menu with \"title, about, exit\" options\nvoid os_tray( const char *tray_name, const char *tray_icon_pathfile ) {\n    static int ever = 0;\n    if( !ever ) {\n        ever = 1;\n        TRAY_NAME = strdup(tray_name);\n        TRAY_ICON_PATHFILE = strdup(tray_icon_pathfile);\n        CreateThread(NULL, 0, SystrayThread, NULL, 0, NULL);\n        while(!tray_window) Sleep(10);\n    }\n}\n#else\nvoid os_tray( const char *title, const char *icon )\n{}\n#endif\n\n#if defined TRAY_DEMO && defined TRAY_C\nint main() {\n    os_tray( \"my demo\", \"demo.ico\" );\n    system(\"pause\");\n}\n#define main main__\n#endif // TRAY_DEMO\n#endif // TRAY_C\n"
  },
  {
    "path": "vault/syn.c",
    "content": "// - rlyeh, public domain\n\n#ifdef SYN_C\n#pragma once\n#define ATOMIC_C\n#define CHANNEL_C\n#define CONDV_C\n#define MCMP_C\n#define MUTEX_C\n#define SEMAPHORE_C\n#define SLEEP_C\n#define THREAD_C\n#define TLS_C\n#define CORO_C\n#define FIBER_C\n#endif\n\n#include \"c.c\"\n#include \"os.c\"\n#include \"syn_mutex.c\"\n#include \"syn_condv.c\"   // after mutex\n#include \"syn_channel.c\" // after condv+mutex\n#include \"syn_tls.c\"\n#include \"syn_thread.c\"  // after tls\n#include \"syn_atomic.c\"\n#include \"syn_mcmp.c\"\n#include \"syn_semaphore.c\"\n#include \"syn_sleep.c\"\n\n#include \"syn_coro.c\"\n#include \"syn_fiber.c\"\n"
  },
  {
    "path": "vault/syn_atomic.c",
    "content": "// # atomics ##################################################################\n// - rlyeh, public domain\n//\n// looking for better coverage? check pfx_compiler.h by @mmozeiko (public domain)\n\n#ifndef ATOMIC_H\n#define ATOMIC_H\n#include <stdint.h>\n\nint64_t atomic_set( int64_t *ptr, const int value );\nint64_t atomic_get( int64_t *ptr );\nint64_t atomic_inc( int64_t *ptr );\nint64_t atomic_dec( int64_t *ptr );\n\n#endif\n\n#ifdef ATOMIC_C\n#pragma once\n#  if defined _MSC_VER\n#   include <intrin.h>\n#   define __sync_add_and_fetch(p,x)               (_InterlockedExchangeAdd64((__int64 volatile *)(p), (x)) + (x))\n#   define __sync_bool_compare_and_swap(p, c, s)   (_InterlockedCompareExchange64((__int64 volatile *)(p), (__int64)(s), (__int64)(c)) == (__int64)(c))\n#   define __sync_lock_test_and_set(p,v)           (_InterlockedExchange64( (__int64 volatile *)(p), (__int64)(v) ))\n#elif defined __TINYC__\n#   include <winnt.h>\n#   define __sync_add_and_fetch(p,x)               (__int64)(InterlockedExchangeAdd((LONG volatile *)(p), (x)) + (x))\n#   define __sync_bool_compare_and_swap(p, c, s)   (__int64)(InterlockedCompareExchange((LONG volatile *)(p), (__int32)(s), (__int32)(c)) == (__int32)(c))\n#   define __sync_lock_test_and_set(p,v)           (__int64)(InterlockedExchange( (LONG volatile *)(p), (__int32)(v) ))\n#   pragma message(\"TODO: Warning! 32-bit atomics untested\")\n#else\n#endif\n\nint64_t atomic_set( int64_t *ptr, const int value ) {\n    return __sync_lock_test_and_set( ptr, value );\n}\nint64_t atomic_get( int64_t *ptr ) {\n    return __sync_add_and_fetch( ptr,  0 );\n}\nint64_t atomic_inc( int64_t *ptr ) {\n    return __sync_add_and_fetch( ptr, +1 );\n}\nint64_t atomic_dec( int64_t *ptr ) {\n    return __sync_add_and_fetch( ptr, -1 );\n}\n\n#ifdef ATOMIC_DEMO\n#include <assert.h>\n#include <stdio.h>\nint main() {\n    int64_t k = 0;\n    assert( atomic_set(&k, 123) ==   0 );\n    assert( atomic_set(&k, 123) == 123 );\n    assert( atomic_get(&k) == 123 );\n    atomic_dec(&k);\n    assert( atomic_get(&k) == 122 );\n    atomic_inc(&k);\n    assert( atomic_get(&k) == 123 );\n    assert( puts(\"ok\") >= 0 );\n}\n#define main main__\n#endif // ATOMIC_DEMO\n#endif // ATOMIC_C\n\n\n"
  },
  {
    "path": "vault/syn_channel.c",
    "content": "// # channels #################################################################\n// - rlyeh, public domain\n//\n// [src] based on cchan library by Máté Nagy (Public Domain)\n//\n// Go-style construct for inter-thread communication: each channel is a FIFO of\n// fixed-length messages, which grows to make space for unread messages.\n// - Multiple threads can write into one channel at once. Writes never block.\n// - Multiple threads can read from one channel at once - but each message is\n//   received only once. If there are multiple parallel readers, a random reader\n//   will get each message.\n\n#ifndef CHANNEL_H\n#define CHANNEL_H\n\n// - create a new channel\n// - destroy channel (not thread-safe..)\n// - put value in channel (never blocks)\n// - get value from channel (return nonzero on success, doesn't block)\n// - get value from channel (blocks until a value is available, or ms milliseconds have elapsed)\n//   returns nonzero on success, zero on timeout\n\ntypedef struct channel channel;\n\nchannel* channel_init(int valuesize);\nvoid     channel_quit(channel *chan);\nvoid     channel_send(channel *chan, void *value);\nint      channel_recv(channel *chan, void *output);\nint      channel_wait(channel *chan, void *output, int ms);\n\n#endif\n\n#ifdef CHANNEL_C\n#pragma once\n#include <stdlib.h>\n#include <string.h>\n//#include \"async_mutex.c\"\n//#include \"async_condv.c\"\n\nstruct channel {\n    int alloc;   // allocated entries in *data\n    int next;    // index of next written entry\n    int first;   // index of first contained entry\n    int used;    // number of used entries\n    int size;    // size of one value\n    char *data;  // queue data\n\n    mutex mutex; // used to lock the channel\n    condv condv; // used to signal availability of data\n};\n\nchannel* channel_init(int valuesize) {\n    channel* c = (channel*)REALLOC(0, sizeof (channel));\n    if(!c) abort();\n\n    c->size = valuesize;\n    c->alloc = 1;\n    c->next = 0;\n    c->first = 0;\n    c->used = 0;\n    c->data = (char*)REALLOC(0, c->alloc * valuesize);\n    if(!c->data) abort();\n\n    mutex_new(&c->mutex);\n    condv_init(&c->condv);\n\n    return c;\n}\n\nvoid channel_quit(channel *chan) {\n    mutex_del(&chan->mutex);\n    condv_quit(&chan->condv);\n\n    REALLOC(chan->data, 0);\n    REALLOC(chan, 0);\n}\n\nvoid channel_send(channel *chan, void *value) {\n    int i;\n\n    mutex_acquire(&chan->mutex);\n\n    if(chan->used == chan->alloc) {\n        // need to expand channel buffer \n\n        i = chan->alloc; // save old buffer size \n\n        chan->alloc *= 2;\n\n        chan->data = (char*)REALLOC(chan->data, chan->alloc * chan->size);\n        if(!chan->data) {\n            puts(\"error: no mem!\");\n            abort();\n        }\n\n        // move part of buffer from beginning until the first contained entry\n        // after the previous end of the buffer\n        // [34512] ->\n        // [   12345   ]\n\n        memcpy(chan->data + i * chan->size, chan->data, chan->first * chan->size);\n        chan->next = i + chan->first;\n    }\n\n    memcpy(chan->data + chan->next * chan->size, value, chan->size);\n    chan->next ++;\n    if(chan->next == chan->alloc) chan->next = 0;\n    chan->used ++;\n\n    condv_emit(&chan->condv);\n\n    mutex_release(&chan->mutex);\n}\n\n// get value from channel (return nonzero on success, doesn't block)\nint channel_recv(channel *chan, void *output) {\n    mutex_acquire(&chan->mutex);\n    if(!chan->used) {\n        mutex_release(&chan->mutex);\n        return 0;\n    }\n\n    memcpy(output, chan->data + chan->first * chan->size, chan->size);\n\n    chan->first ++;\n    if(chan->first == chan->alloc) chan->first = 0;\n\n    chan->used --;\n\n    mutex_release(&chan->mutex);\n\n    return 1;\n}\n\n// get value from channel (blocks until a value is available, or ms milliseconds have elapsed)\n// returns nonzero on success, zero on timeout\nint channel_wait(channel *chan, void *output, int ms) {\n    mutex_acquire(&chan->mutex);\n\n    if(chan->used) {\n        memcpy(output, chan->data + chan->first * chan->size, chan->size);\n        chan->first ++;\n        if(chan->first == chan->alloc) chan->first = 0;\n        chan->used --;\n        mutex_release(&chan->mutex);\n        return 1;\n    }\n\n    condv_wait(&chan->condv, &chan->mutex, ms);\n\n    if(chan->used) {\n        memcpy(output, chan->data + chan->first * chan->size, chan->size);\n        chan->first ++;\n        if(chan->first == chan->alloc) chan->first = 0;\n        chan->used --;\n        mutex_release(&chan->mutex);\n        return 1;\n    } else {\n        mutex_release(&chan->mutex);\n        return 0;\n    }\n}\n\n#endif\n\n#if CHANNEL_BENCH\n#include <assert.h>\n#include <omp.h>\n#include <stdio.h>\n#include \"async_thread.c\"\nenum { N = 10, M = 1000 * 1000 };\nvoid async_send( void *args ) {\n    channel *c = (channel*)args;\n    for( int i = 0; i < N*M; ++i ) {\n        channel_send(c, &i);\n    }\n}\nint main() {\n    double t = omp_get_wtime();\n    channel *c = channel_init( sizeof(int) );\n    detach( async_send, c );\n    for( int i = 0; i < N*M; ++i ) {\n        int answer;\n        channel_wait(c, &answer, 0);\n        assert( answer == i );\n    }\n    channel_quit(c);\n    t = omp_get_wtime() - t;\n    int ops = (2*N*M)+2;\n    printf(\"%5.2fs %5.2fM ops/s\\n\", t, (ops / t) / M);\n}\n#endif\n\n\n#if CHANNEL_DEMO\n#include <stdio.h>\nvoid pstate(channel *chan) {\n    int i, v;\n\n    printf(\"----------------------- chan %p\\n\", (void *) chan);\n    printf(\"alloc=%d next=%d first=%d used=%d\\n\", chan->alloc, chan->next, chan->first, chan->used);\n\n    printf(\"[\");\n    for(i=0; i<chan->alloc; i++) {\n        v = * (int *) (chan->data + i * chan->size);\n        if(v >= 'a' && v <= 'z')\n            printf(\"%c\", v);\n        else\n            printf(\".\");\n    }\n    printf(\"]\\n\");\n\n    printf(\"\\n\");\n}\nvoid precv(channel *chan) {\n    int out;\n    int res = channel_wait(chan, &out, 1000);\n\n    if(!res) {\n        printf(\"recv fail\\n\");\n    } else {\n        printf(\"recv = %c\\n\", out);\n    }\n}\nint main() {\n    channel *c1 = channel_init(sizeof(int));\n    int v;\n\n    pstate(c1);\n\n    v = 'a'; channel_send(c1, &v);\n\n    pstate(c1);\n\n    v = 'b'; channel_send(c1, &v);\n    v = 'c'; channel_send(c1, &v);\n\n    pstate(c1);\n\n    precv(c1);\n    precv(c1);\n\n    pstate(c1);\n\n    v = 'd'; channel_send(c1, &v);\n    v = 'e'; channel_send(c1, &v);\n    v = 'f'; channel_send(c1, &v);\n\n    pstate(c1);\n\n    v = 'g';\n    channel_send(c1, &v);\n\n    pstate(c1);\n\n    precv(c1);\n    precv(c1);\n    precv(c1);\n    precv(c1);\n    precv(c1);\n    precv(c1); // should this fail\n\n    channel_quit(c1);\n}\n#endif\n"
  },
  {
    "path": "vault/syn_condv.c",
    "content": "// # condition variables ######################################################\n// - rlyeh, public domain\n\n#ifndef CONDV_H\n#define CONDV_H\n\ntypedef union condv {\n    char opaque_cpp_x64_vs2013[16];\n    char opaque_cpp_x64_vs2015[88];\n    char opaque_cpp_x64_vs2017[88];\n    char opaque_cpp_x86_vs2013[8];\n    char opaque_cpp_x86_vs2015[48];\n    char opaque_cpp_x86_vs2017[48];\n    char opaque_win_x64_vs2013[8];\n    char opaque_win_x64_vs2015[8];\n    char opaque_win_x64_vs2017[8];\n    char opaque_win_x86_vs2013[4];\n    char opaque_win_x86_vs2015[4];\n    char opaque_win_x86_vs2017[4];\n} condv;\n\nvoid condv_init( condv *c );\nvoid condv_quit( condv *c );\nvoid condv_emit( condv *c );\nvoid condv_wait( condv *c, void *mutex, int ms );\n\n#endif\n\n#ifdef CONDV_C\n#pragma once\n//#include \"async_mutex.c\"\n\n#if defined(__cplusplus)\n#   include <chrono>\n#   include <condition_variable>\n#   include <mutex>\n#   define CONDV_API                       \"cpp\"\n#   define condv_t                          std::condition_variable_any\n#   define condv_initial(condv)             (new (condv) condv_t)\n#   define condv_destroy(condv)             ((condv)->~condition_variable_any())\n#   define condv_signal(condv)              ((condv)->notify_one())\n#   define condv_timedwait(condv,mt,ms)     ((condv)->wait_for(std::unique_lock<mutex_t>(*(mt)), std::chrono::milliseconds(ms)))\n#elif defined(__TINYC__) // not supported\n//#   include <winsock2.h>\n#   define CONDV_API                       \"tcc\"\n#   define condv_t                          int\n#   define condv_initial(condv)             ((void)0)\n#   define condv_destroy(condv)             ((void)0)\n#   define condv_signal(condv)              ((void)0)\n#   define condv_timedwait(condv,mt,ms)     ((void)0)\n#elif defined(_WIN32)\n//#   include <winsock2.h>\n#   define CONDV_API                       \"win\"\n#   define condv_t                          CONDITION_VARIABLE\n#   define condv_initial(condv)             (InitializeConditionVariable((condv)))\n#   define condv_destroy(condv)             ((void)0)\n#   define condv_signal(condv)              (WakeConditionVariable((condv)))\n#   define condv_timedwait(condv,mt,ms)     (SleepConditionVariableCS((condv), (PCRITICAL_SECTION)(mt), (ms) ? (ms) : INFINITE))\n#else\n#   include <pthread.h>\n#   include <sys/time.h>\n#   define CONDV_API                       \"pth\"\n#   define condv_t                          pthread_cond_t\n#   define condv_initial(condv)             (pthread_cond_init(condv, NULL))\n#   define condv_destroy(condv)             (pthread_cond_destroy(condv))\n#   define condv_signal(condv)              (pthread_cond_signal(condv))\n//# define condv_timedwait(condv,mt,ms)     (pthread_cond_timedwait(condv,mt,ms))\nstatic int condv_timedwait( condv_t *c, mutex *m, int ms ) {\n    if( !ms ) {\n        pthread_cond_wait(c, m);\n        return 1;\n    } else {\n        struct timeval now;\n        struct timespec timeout;\n        gettimeofday(&now, NULL);\n\n        timeout.tv_sec = now.tv_sec + ms / 1000;\n        timeout.tv_nsec = (now.tv_usec + (ms % 1000) * 1000) * 1000;\n        if(timeout.tv_nsec > 1000000000) {\n            timeout.tv_nsec -= 1000000000;\n            timeout.tv_sec ++;\n        }\n        return pthread_cond_timedwait(c, m, &timeout);\n    }\n}\n#endif\n\ntypedef int condv__is_large_enough[ sizeof(condv) >= sizeof(condv_t) ];\n\nconst char *condv_api = CONDV_API;\n\nvoid condv_init( condv *c ) {\n    condv_initial((condv_t*)c);\n}\nvoid condv_quit( condv *c ) {\n    condv_destroy((condv_t*)c);\n}\nvoid condv_emit( condv *c ) {\n    condv_signal((condv_t*)c);\n}\nvoid condv_wait( condv *c, void *m, int ms ) {\n    condv_timedwait( (condv_t*)c, (mutex*)m, ms );\n}\n\n#endif\n\n\n#if CONDV_DEMO\n#include <assert.h>\n#include <stdio.h>\n#include \"async_thread.c\"\n\nint main() {\n\n#ifdef _MSC_VER\n    const char *msc = \"vs-deprecated\";\n    /**/ if(_MSC_VER >= 1910) msc = \"vs2017\";\n    else if(_MSC_VER >= 1900) msc = \"vs2015\";\n    else if(_MSC_VER >= 1800) msc = \"vs2013\";\n    else if(_MSC_VER >= 1700) msc = \"vs2012\";\n    else if(_MSC_VER >= 1600) msc = \"vs2010\";\n    else if(_MSC_VER >= 1500) msc = \"vs2008\";\n    else if(_MSC_VER >= 1400) msc = \"vs2005\";\n    else if(_MSC_VER >= 1310) msc = \"vs2003\";\n\n#ifdef _WIN64\n    printf(\"char opaque_%s_%s_%s[%d];\\n\", condv_api, \"x64\", msc, (int)sizeof(condv_t));\n#else\n    printf(\"char opaque_%s_%s_%s[%d];\\n\", condv_api, \"x32\", msc, (int)sizeof(condv_t));\n#endif\n\n#endif\n\n    mutex m = {0};\n    mutex_new( &m );\n\n    condv c = {0};\n    condv_init( &c );\n\n    detach( condv_emit, &c );\n    condv_wait( &c, &m, 1000 );\n\n    condv_quit( &c );\n    assert( puts(\"ok\") >= 0 );\n}\n#endif\n"
  },
  {
    "path": "vault/syn_coro.c",
    "content": "// from randypgaul https://github.com/RandyGaul/kk_slides (likely public domain)\n\n#pragma once\n\ntypedef struct coroutine_t {\n    float elapsed;\n    int index;\n} coroutine_t;\n\n#define COROUTINE_BEGIN(co) do { switch (co->index) { default:\n#define COROUTINE_CASE(co, name) case __LINE__: name: co->index = __LINE__;\n#define COROUTINE_GOTO(co, name) do { goto name; } while (0)\n#define COROUTINE_EXIT(co) do { goto __co_end; } while (0)\n#define COROUTINE_YIELD(co) do { co->index = __LINE__; COROUTINE_EXIT(co); case __LINE__:; } while (0)\n#define COROUTINE_WAIT(co, time, dt) do { case __LINE__: co->index = __LINE__; co->elapsed += dt; if(co->elapsed < time) goto __co_end; co->elapsed = 0; } while (0)\n#define COROUTINE_END(co) } co->index = 0; __co_end:; } while (0)\n\n/*\n#include <stdio.h>\n#include <winsock2.h> // Sleep\n\nvoid test1(coroutine_t* co) {\n    static int loop_count = 0;\n\n    COROUTINE_BEGIN(co);\n\n    COROUTINE_CASE(co, loop_start);\n    printf(\"State 0\\n\");\n    COROUTINE_YIELD(co);\n    printf(\"State 1\\n\");\n    COROUTINE_YIELD(co);\n    printf(\"State 2\\n\");\n    COROUTINE_YIELD(co);\n    // [...]\n    COROUTINE_GOTO(co, loop_start);\n\n    COROUTINE_END(co);\n}\n\nint test2(coroutine_t* co, float dt) {\n    int active = 1;\n\n    printf(\"%.1f\\r\", co->elapsed);\n\n    COROUTINE_BEGIN(co);\n\n    COROUTINE_WAIT(co, 0.0f, dt);\n    printf(\"State 0\\n\");\n    COROUTINE_WAIT(co, 1.0f, dt);\n    printf(\"State 1\\n\");\n    COROUTINE_WAIT(co, 2.0f, dt);\n    printf(\"State 2\\n\");\n    active = 0;\n\n    COROUTINE_END(co);\n    return active;\n}\n\nint main() {\n    coroutine_t co1 = {0};\n    for(int i = 0; i < 6; ++i) test1(&co1);\n    puts(\"---\");\n\n    coroutine_t co2 = {0};\n    while(test2(&co2, 1.0/60)) Sleep(10); // should be 16 instead of 10; but Sleep() precision sucks\n}\n*/\n"
  },
  {
    "path": "vault/syn_fiber.c",
    "content": "/*\n  libco v18 (2016-09-14)\n  author: byuu\n  license: public domain\n  libco is released to the public domain by John MacFarlane (2013-2016)\n  http://byuu.org/library/libco/\n\n## libco.x86\n- Overhead: ~5x\n- Supported processor(s): 32-bit x86\n- Supported compiler(s): any\n- Supported operating system(s):\n  - Windows\n  - Mac OS X\n  - Linux\n  - BSD\n\n## libco.amd64\n- Overhead: ~10x (Windows), ~6x (all other platforms)\n- Supported processor(s): 64-bit amd64\n- Supported compiler(s): any\n- Supported operating system(s):\n  - Windows\n  - Mac OS X\n  - Linux\n  - BSD\n\n## libco.ppc\n- Overhead: ~20x\n- Supported processor(s): 32-bit PowerPC, 64-bit PowerPC\n- Supported compiler(s): GNU GCC\n- Supported operating system(s):\n  - Mac OS X\n  - Linux\n  - BSD\n  - Playstation 3\n- Note: this module contains compiler flags to enable/disable FPU and Altivec support.\n\n## libco.fiber\n- Overhead: ~15x\n- Supported processor(s): Processor independent\n- Supported compiler(s): any\n- Supported operating system(s):\n  - Windows\n\n## libco.sjlj\n- Overhead: ~30x\n- Supported processor(s): Processor independent\n- Supported compiler(s): any\n- Supported operating system(s):\n  - Mac OS X\n  - Linux\n  - BSD\n  - Solaris\n\n## libco.ucontext\n- Overhead: ~300x (beware!!)\n- Supported processor(s): Processor independent\n- Supported compiler(s): any\n- Supported operating system(s):\n  - Linux\n  - BSD\n*/\n\n#ifndef FIBER_H\n#define FIBER_H\n\n#if defined _MSC_VER || defined __TINYC__ // @r-lyeh\n#define LIBCO_MP\n#define LIBCO_MPROTECT\n#ifndef __thread\n#define __thread __declspec(thread)\n#endif\n#endif\n\n#define fiber         cothread_t\n#define fiber_active  co_active\n#define fiber_create  co_create\n#define fiber_delete  co_delete\n#define fiber_switch  co_switch\n\n// ---\n\ntypedef void* cothread_t;\n\ncothread_t co_active();\ncothread_t co_create(unsigned int, void (*)(void));\nvoid co_delete(cothread_t);\nvoid co_switch(cothread_t);\n\n#endif // FIBER_H\n\n// ---\n\n#ifdef FIBER_C\n#pragma once\n\n/*[amd64, arm, ppc, x86]:\n   by default, co_swap_function is marked as a text (code) section\n   if not supported, uncomment the below line to use mprotect instead */\n/* #define LIBCO_MPROTECT */\n\n/*[amd64]:\n   Win64 only: provides a substantial speed-up, but will thrash XMM regs\n   do not use this unless you are certain your application won't use SSE */\n/* #define LIBCO_NO_SSE */\n\n#if defined(__clang__)\n  #pragma clang diagnostic ignored \"-Wparentheses\"\n#endif\n\n#if defined(__clang__) || defined(__GNUC__)\n  #if defined(__i386__)\n    #include \"syn_fiber_x86.h\"\n  #elif defined(__amd64__)\n    #include \"syn_fiber_amd64.h\"\n  #elif defined(__arm__)\n    #include \"syn_fiber_arm.h\"\n  /* FIXME: co_create crashes on ppc64el */\n  /*#elif defined(_ARCH_PPC)\n    #include \"syn_fiber_ppc.h\" */\n  #elif defined(_WIN32)\n    #include \"syn_fiber_win32.h\"\n  #else\n    #include \"syn_fiber_sjlj.h\"\n  #endif\n#elif defined(_MSC_VER)\n  #if defined(_M_IX86)\n    #include \"syn_fiber_x86.h\"\n  #elif defined(_M_AMD64)\n    #include \"syn_fiber_amd64.h\"\n  #else\n    #include \"syn_fiber_win32.h\"\n  #endif\n#elif defined(__TINYC__)\n    #include \"syn_fiber_win32.h\"\n#else\n  #error \"fiber: libco: unsupported processor, compiler or operating system\"\n#endif\n\n#ifdef FIBER_DEMO\n#include <stdio.h>\n#include <stdlib.h>\nfiber self; // ~main_thread\nvoid my_entry(void) {\n    for(;;) {\n        puts(\"1\");\n        fiber_switch(self);\n        puts(\"2\");\n        fiber_switch(self);\n    }\n    exit(0); // unreachable\n}\nint main() {\n    self = fiber_active();\n\n    fiber coro = fiber_create(1*1024*1024, my_entry); // 1MiB; 64K instead?\n    fiber_switch(coro);\n    fiber_switch(coro);\n    fiber_switch(coro);\n\n    fiber_delete(coro);\n}\n#define main main__\n#endif // FIBER_DEMO\n#endif // FIBER_C\n"
  },
  {
    "path": "vault/syn_fiber_amd64.h",
    "content": "/*\n  libco.amd64 (2016-09-14)\n  author: byuu\n  license: public domain\n*/\n\n#include <assert.h>\n#include <stdlib.h>\n\nstatic THREAD long long co_active_buffer[64];\nstatic THREAD cothread_t co_active_handle = 0;\nstatic void (*co_swap)(cothread_t, cothread_t) = 0;\n\n#ifdef LIBCO_MPROTECT\n  ALIGNAS(4096)\n#else\n  SECTION(text)\n#endif\n#ifdef _WIN32\n  /* ABI: Win64 */\n  static const unsigned char co_swap_function[4096] = {\n    0x48, 0x89, 0x22,              /* mov [rdx],rsp          */\n    0x48, 0x8b, 0x21,              /* mov rsp,[rcx]          */\n    0x58,                          /* pop rax                */\n    0x48, 0x89, 0x6a, 0x08,        /* mov [rdx+ 8],rbp       */\n    0x48, 0x89, 0x72, 0x10,        /* mov [rdx+16],rsi       */\n    0x48, 0x89, 0x7a, 0x18,        /* mov [rdx+24],rdi       */\n    0x48, 0x89, 0x5a, 0x20,        /* mov [rdx+32],rbx       */\n    0x4c, 0x89, 0x62, 0x28,        /* mov [rdx+40],r12       */\n    0x4c, 0x89, 0x6a, 0x30,        /* mov [rdx+48],r13       */\n    0x4c, 0x89, 0x72, 0x38,        /* mov [rdx+56],r14       */\n    0x4c, 0x89, 0x7a, 0x40,        /* mov [rdx+64],r15       */\n  #if !defined(LIBCO_NO_SSE)\n    0x0f, 0x29, 0x72, 0x50,        /* movaps [rdx+ 80],xmm6  */\n    0x0f, 0x29, 0x7a, 0x60,        /* movaps [rdx+ 96],xmm7  */\n    0x44, 0x0f, 0x29, 0x42, 0x70,  /* movaps [rdx+112],xmm8  */\n    0x48, 0x83, 0xc2, 0x70,        /* add rdx,112            */\n    0x44, 0x0f, 0x29, 0x4a, 0x10,  /* movaps [rdx+ 16],xmm9  */\n    0x44, 0x0f, 0x29, 0x52, 0x20,  /* movaps [rdx+ 32],xmm10 */\n    0x44, 0x0f, 0x29, 0x5a, 0x30,  /* movaps [rdx+ 48],xmm11 */\n    0x44, 0x0f, 0x29, 0x62, 0x40,  /* movaps [rdx+ 64],xmm12 */\n    0x44, 0x0f, 0x29, 0x6a, 0x50,  /* movaps [rdx+ 80],xmm13 */\n    0x44, 0x0f, 0x29, 0x72, 0x60,  /* movaps [rdx+ 96],xmm14 */\n    0x44, 0x0f, 0x29, 0x7a, 0x70,  /* movaps [rdx+112],xmm15 */\n  #endif\n    0x48, 0x8b, 0x69, 0x08,        /* mov rbp,[rcx+ 8]       */\n    0x48, 0x8b, 0x71, 0x10,        /* mov rsi,[rcx+16]       */\n    0x48, 0x8b, 0x79, 0x18,        /* mov rdi,[rcx+24]       */\n    0x48, 0x8b, 0x59, 0x20,        /* mov rbx,[rcx+32]       */\n    0x4c, 0x8b, 0x61, 0x28,        /* mov r12,[rcx+40]       */\n    0x4c, 0x8b, 0x69, 0x30,        /* mov r13,[rcx+48]       */\n    0x4c, 0x8b, 0x71, 0x38,        /* mov r14,[rcx+56]       */\n    0x4c, 0x8b, 0x79, 0x40,        /* mov r15,[rcx+64]       */\n  #if !defined(LIBCO_NO_SSE)\n    0x0f, 0x28, 0x71, 0x50,        /* movaps xmm6, [rcx+ 80] */\n    0x0f, 0x28, 0x79, 0x60,        /* movaps xmm7, [rcx+ 96] */\n    0x44, 0x0f, 0x28, 0x41, 0x70,  /* movaps xmm8, [rcx+112] */\n    0x48, 0x83, 0xc1, 0x70,        /* add rcx,112            */\n    0x44, 0x0f, 0x28, 0x49, 0x10,  /* movaps xmm9, [rcx+ 16] */\n    0x44, 0x0f, 0x28, 0x51, 0x20,  /* movaps xmm10,[rcx+ 32] */\n    0x44, 0x0f, 0x28, 0x59, 0x30,  /* movaps xmm11,[rcx+ 48] */\n    0x44, 0x0f, 0x28, 0x61, 0x40,  /* movaps xmm12,[rcx+ 64] */\n    0x44, 0x0f, 0x28, 0x69, 0x50,  /* movaps xmm13,[rcx+ 80] */\n    0x44, 0x0f, 0x28, 0x71, 0x60,  /* movaps xmm14,[rcx+ 96] */\n    0x44, 0x0f, 0x28, 0x79, 0x70,  /* movaps xmm15,[rcx+112] */\n  #endif\n    0xff, 0xe0,                    /* jmp rax                */\n  };\n\n  #include <windows.h>\n\n  static void co_init() {\n    #ifdef LIBCO_MPROTECT\n    DWORD old_privileges;\n    VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);\n    #endif\n  }\n#else\n  /* ABI: SystemV */\n  static const unsigned char co_swap_function[4096] = {\n    0x48, 0x89, 0x26,        /* mov [rsi],rsp    */\n    0x48, 0x8b, 0x27,        /* mov rsp,[rdi]    */\n    0x58,                    /* pop rax          */\n    0x48, 0x89, 0x6e, 0x08,  /* mov [rsi+ 8],rbp */\n    0x48, 0x89, 0x5e, 0x10,  /* mov [rsi+16],rbx */\n    0x4c, 0x89, 0x66, 0x18,  /* mov [rsi+24],r12 */\n    0x4c, 0x89, 0x6e, 0x20,  /* mov [rsi+32],r13 */\n    0x4c, 0x89, 0x76, 0x28,  /* mov [rsi+40],r14 */\n    0x4c, 0x89, 0x7e, 0x30,  /* mov [rsi+48],r15 */\n    0x48, 0x8b, 0x6f, 0x08,  /* mov rbp,[rdi+ 8] */\n    0x48, 0x8b, 0x5f, 0x10,  /* mov rbx,[rdi+16] */\n    0x4c, 0x8b, 0x67, 0x18,  /* mov r12,[rdi+24] */\n    0x4c, 0x8b, 0x6f, 0x20,  /* mov r13,[rdi+32] */\n    0x4c, 0x8b, 0x77, 0x28,  /* mov r14,[rdi+40] */\n    0x4c, 0x8b, 0x7f, 0x30,  /* mov r15,[rdi+48] */\n    0xff, 0xe0,              /* jmp rax          */\n  };\n\n  #include <unistd.h>\n  #include <sys/mman.h>\n\n  static void co_init() {\n    #ifdef LIBCO_MPROTECT\n    unsigned long long addr = (unsigned long long)co_swap_function;\n    unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));\n    unsigned long long size = (addr - base) + sizeof co_swap_function;\n    mprotect((void*)base, size, PROT_READ | PROT_EXEC);\n    #endif\n  }\n#endif\n\nstatic void crash() {\n  assert(0);  /* called only if cothread_t entrypoint returns */\n}\n\ncothread_t co_active() {\n  if(!co_active_handle) co_active_handle = &co_active_buffer;\n  return co_active_handle;\n}\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void)) {\n  cothread_t handle;\n  if(!co_swap) {\n    co_init();\n    co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;\n  }\n  if(!co_active_handle) co_active_handle = &co_active_buffer;\n  size += 512;  /* allocate additional space for storage */\n  size &= ~15;  /* align stack to 16-byte boundary */\n\n  if(handle = (cothread_t)malloc(size)) {\n    long long *p = (long long*)((char*)handle + size);  /* seek to top of stack */\n    *--p = (long long)crash;                            /* crash if entrypoint returns */\n    *--p = (long long)entrypoint;                       /* start of function */\n    *(long long*)handle = (long long)p;                 /* stack pointer */\n  }\n\n  return handle;\n}\n\nvoid co_delete(cothread_t handle) {\n  free(handle);\n}\n\nvoid co_switch(cothread_t handle) {\n  register cothread_t co_previous_handle = co_active_handle;\n  co_swap(co_active_handle = handle, co_previous_handle);\n}\n"
  },
  {
    "path": "vault/syn_fiber_arm.h",
    "content": "/*\n  libco.arm (2016-09-14)\n  author: byuu\n  license: public domain\n*/\n\n#include <assert.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/mman.h>\n\nstatic THREAD unsigned long co_active_buffer[64];\nstatic THREAD cothread_t co_active_handle = 0;\nstatic void (*co_swap)(cothread_t, cothread_t) = 0;\n\n#ifdef LIBCO_MPROTECT\n  ALIGNAS(4096)\n#else\n  SECTION(text)\n#endif\nstatic const unsigned long co_swap_function[1024] = {\n  0xe8a16ff0,  /* stmia r1!, {r4-r11,sp,lr} */\n  0xe8b0aff0,  /* ldmia r0!, {r4-r11,sp,pc} */\n  0xe12fff1e,  /* bx lr                     */\n};\n\nstatic void co_init() {\n  #ifdef LIBCO_MPROTECT\n  unsigned long addr = (unsigned long)co_swap_function;\n  unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));\n  unsigned long size = (addr - base) + sizeof co_swap_function;\n  mprotect((void*)base, size, PROT_READ | PROT_EXEC);\n  #endif\n}\n\ncothread_t co_active() {\n  if(!co_active_handle) co_active_handle = &co_active_buffer;\n  return co_active_handle;\n}\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void)) {\n  unsigned long* handle = 0;\n  if(!co_swap) {\n    co_init();\n    co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;\n  }\n  if(!co_active_handle) co_active_handle = &co_active_buffer;\n  size += 256;\n  size &= ~15;\n\n  if(handle = (unsigned long*)malloc(size)) {\n    unsigned long* p = (unsigned long*)((unsigned char*)handle + size);\n    handle[8] = (unsigned long)p;\n    handle[9] = (unsigned long)entrypoint;\n  }\n\n  return handle;\n}\n\nvoid co_delete(cothread_t handle) {\n  free(handle);\n}\n\n__attribute__((target(\"arm\"))) // @smibarber\nvoid co_switch(cothread_t handle) {\n  cothread_t co_previous_handle = co_active_handle;\n  co_swap(co_active_handle = handle, co_previous_handle);\n}\n"
  },
  {
    "path": "vault/syn_fiber_ppc.h",
    "content": "/*\n  libco.ppc (2016-09-14)\n  author: blargg\n  license: public domain\n*/\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#if LIBCO_MPROTECT\n  #include <unistd.h>\n  #include <sys/mman.h>\n#endif\n\n/* state format (offsets in 32-bit words)\n\n +0 pointer to swap code\n    rest of function descriptor for entry function\n +8 PC\n+10 SP\n    special registers\n    GPRs\n    FPRs\n    VRs\n    stack\n*/\n\nenum { state_size  = 1024 };\nenum { above_stack = 2048 };\nenum { stack_align = 256  };\n\nstatic THREAD cothread_t co_active_handle = 0;\n\n/* determine environment */\n\n#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)\n\n/* whether function calls are indirect through a descriptor, or are directly to function */\n#ifndef LIBCO_PPCDESC\n  #if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)\n    #define LIBCO_PPCDESC 1\n  #endif\n#endif\n\n#ifdef LIBCO_MPROTECT\n  ALIGNAS(4096)\n#else\n  SECTION(text)\n#endif\nstatic const uint32_t libco_ppc_code[1024] = {\n  #if LIBCO_PPC64\n  0x7d000026,  /* mfcr    r8          */\n  0xf8240028,  /* std     r1,40(r4)   */\n  0x7d2802a6,  /* mflr    r9          */\n  0xf9c40048,  /* std     r14,72(r4)  */\n  0xf9e40050,  /* std     r15,80(r4)  */\n  0xfa040058,  /* std     r16,88(r4)  */\n  0xfa240060,  /* std     r17,96(r4)  */\n  0xfa440068,  /* std     r18,104(r4) */\n  0xfa640070,  /* std     r19,112(r4) */\n  0xfa840078,  /* std     r20,120(r4) */\n  0xfaa40080,  /* std     r21,128(r4) */\n  0xfac40088,  /* std     r22,136(r4) */\n  0xfae40090,  /* std     r23,144(r4) */\n  0xfb040098,  /* std     r24,152(r4) */\n  0xfb2400a0,  /* std     r25,160(r4) */\n  0xfb4400a8,  /* std     r26,168(r4) */\n  0xfb6400b0,  /* std     r27,176(r4) */\n  0xfb8400b8,  /* std     r28,184(r4) */\n  0xfba400c0,  /* std     r29,192(r4) */\n  0xfbc400c8,  /* std     r30,200(r4) */\n  0xfbe400d0,  /* std     r31,208(r4) */\n  0xf9240020,  /* std     r9,32(r4)   */\n  0xe8e30020,  /* ld      r7,32(r3)   */\n  0xe8230028,  /* ld      r1,40(r3)   */\n  0x48000009,  /* bl      1           */\n  0x7fe00008,  /* trap                */\n  0x91040030, /*1:stw     r8,48(r4)   */\n  0x80c30030,  /* lwz     r6,48(r3)   */\n  0x7ce903a6,  /* mtctr   r7          */\n  0xe9c30048,  /* ld      r14,72(r3)  */\n  0xe9e30050,  /* ld      r15,80(r3)  */\n  0xea030058,  /* ld      r16,88(r3)  */\n  0xea230060,  /* ld      r17,96(r3)  */\n  0xea430068,  /* ld      r18,104(r3) */\n  0xea630070,  /* ld      r19,112(r3) */\n  0xea830078,  /* ld      r20,120(r3) */\n  0xeaa30080,  /* ld      r21,128(r3) */\n  0xeac30088,  /* ld      r22,136(r3) */\n  0xeae30090,  /* ld      r23,144(r3) */\n  0xeb030098,  /* ld      r24,152(r3) */\n  0xeb2300a0,  /* ld      r25,160(r3) */\n  0xeb4300a8,  /* ld      r26,168(r3) */\n  0xeb6300b0,  /* ld      r27,176(r3) */\n  0xeb8300b8,  /* ld      r28,184(r3) */\n  0xeba300c0,  /* ld      r29,192(r3) */\n  0xebc300c8,  /* ld      r30,200(r3) */\n  0xebe300d0,  /* ld      r31,208(r3) */\n  0x7ccff120,  /* mtcr    r6          */\n  #else\n  0x7d000026,  /* mfcr    r8          */\n  0x90240028,  /* stw     r1,40(r4)   */\n  0x7d2802a6,  /* mflr    r9          */\n  0x91a4003c,  /* stw     r13,60(r4)  */\n  0x91c40040,  /* stw     r14,64(r4)  */\n  0x91e40044,  /* stw     r15,68(r4)  */\n  0x92040048,  /* stw     r16,72(r4)  */\n  0x9224004c,  /* stw     r17,76(r4)  */\n  0x92440050,  /* stw     r18,80(r4)  */\n  0x92640054,  /* stw     r19,84(r4)  */\n  0x92840058,  /* stw     r20,88(r4)  */\n  0x92a4005c,  /* stw     r21,92(r4)  */\n  0x92c40060,  /* stw     r22,96(r4)  */\n  0x92e40064,  /* stw     r23,100(r4) */\n  0x93040068,  /* stw     r24,104(r4) */\n  0x9324006c,  /* stw     r25,108(r4) */\n  0x93440070,  /* stw     r26,112(r4) */\n  0x93640074,  /* stw     r27,116(r4) */\n  0x93840078,  /* stw     r28,120(r4) */\n  0x93a4007c,  /* stw     r29,124(r4) */\n  0x93c40080,  /* stw     r30,128(r4) */\n  0x93e40084,  /* stw     r31,132(r4) */\n  0x91240020,  /* stw     r9,32(r4)   */\n  0x80e30020,  /* lwz     r7,32(r3)   */\n  0x80230028,  /* lwz     r1,40(r3)   */\n  0x48000009,  /* bl      1           */\n  0x7fe00008,  /* trap                */\n  0x91040030, /*1:stw     r8,48(r4)   */\n  0x80c30030,  /* lwz     r6,48(r3)   */\n  0x7ce903a6,  /* mtctr   r7          */\n  0x81a3003c,  /* lwz     r13,60(r3)  */\n  0x81c30040,  /* lwz     r14,64(r3)  */\n  0x81e30044,  /* lwz     r15,68(r3)  */\n  0x82030048,  /* lwz     r16,72(r3)  */\n  0x8223004c,  /* lwz     r17,76(r3)  */\n  0x82430050,  /* lwz     r18,80(r3)  */\n  0x82630054,  /* lwz     r19,84(r3)  */\n  0x82830058,  /* lwz     r20,88(r3)  */\n  0x82a3005c,  /* lwz     r21,92(r3)  */\n  0x82c30060,  /* lwz     r22,96(r3)  */\n  0x82e30064,  /* lwz     r23,100(r3) */\n  0x83030068,  /* lwz     r24,104(r3) */\n  0x8323006c,  /* lwz     r25,108(r3) */\n  0x83430070,  /* lwz     r26,112(r3) */\n  0x83630074,  /* lwz     r27,116(r3) */\n  0x83830078,  /* lwz     r28,120(r3) */\n  0x83a3007c,  /* lwz     r29,124(r3) */\n  0x83c30080,  /* lwz     r30,128(r3) */\n  0x83e30084,  /* lwz     r31,132(r3) */\n  0x7ccff120,  /* mtcr    r6 */\n  #endif\n\n  #ifndef LIBCO_PPC_NOFP\n  0xd9c400e0,  /* stfd    f14,224(r4) */\n  0xd9e400e8,  /* stfd    f15,232(r4) */\n  0xda0400f0,  /* stfd    f16,240(r4) */\n  0xda2400f8,  /* stfd    f17,248(r4) */\n  0xda440100,  /* stfd    f18,256(r4) */\n  0xda640108,  /* stfd    f19,264(r4) */\n  0xda840110,  /* stfd    f20,272(r4) */\n  0xdaa40118,  /* stfd    f21,280(r4) */\n  0xdac40120,  /* stfd    f22,288(r4) */\n  0xdae40128,  /* stfd    f23,296(r4) */\n  0xdb040130,  /* stfd    f24,304(r4) */\n  0xdb240138,  /* stfd    f25,312(r4) */\n  0xdb440140,  /* stfd    f26,320(r4) */\n  0xdb640148,  /* stfd    f27,328(r4) */\n  0xdb840150,  /* stfd    f28,336(r4) */\n  0xdba40158,  /* stfd    f29,344(r4) */\n  0xdbc40160,  /* stfd    f30,352(r4) */\n  0xdbe40168,  /* stfd    f31,360(r4) */\n  0xc9c300e0,  /* lfd     f14,224(r3) */\n  0xc9e300e8,  /* lfd     f15,232(r3) */\n  0xca0300f0,  /* lfd     f16,240(r3) */\n  0xca2300f8,  /* lfd     f17,248(r3) */\n  0xca430100,  /* lfd     f18,256(r3) */\n  0xca630108,  /* lfd     f19,264(r3) */\n  0xca830110,  /* lfd     f20,272(r3) */\n  0xcaa30118,  /* lfd     f21,280(r3) */\n  0xcac30120,  /* lfd     f22,288(r3) */\n  0xcae30128,  /* lfd     f23,296(r3) */\n  0xcb030130,  /* lfd     f24,304(r3) */\n  0xcb230138,  /* lfd     f25,312(r3) */\n  0xcb430140,  /* lfd     f26,320(r3) */\n  0xcb630148,  /* lfd     f27,328(r3) */\n  0xcb830150,  /* lfd     f28,336(r3) */\n  0xcba30158,  /* lfd     f29,344(r3) */\n  0xcbc30160,  /* lfd     f30,352(r3) */\n  0xcbe30168,  /* lfd     f31,360(r3) */\n  #endif\n\n  #ifdef __ALTIVEC__\n  0x7ca042a6,  /* mfvrsave r5        */\n  0x39040180,  /* addi    r8,r4,384  */\n  0x39240190,  /* addi    r9,r4,400  */\n  0x70a00fff,  /* andi.   r0,r5,4095 */\n  0x90a40034,  /* stw     r5,52(r4)  */\n  0x4182005c,  /* beq-    2          */\n  0x7e8041ce,  /* stvx    v20,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7ea049ce,  /* stvx    v21,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7ec041ce,  /* stvx    v22,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7ee049ce,  /* stvx    v23,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7f0041ce,  /* stvx    v24,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7f2049ce,  /* stvx    v25,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7f4041ce,  /* stvx    v26,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7f6049ce,  /* stvx    v27,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7f8041ce,  /* stvx    v28,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7fa049ce,  /* stvx    v29,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7fc041ce,  /* stvx    v30,r0,r8  */\n  0x7fe049ce,  /* stvx    v31,r0,r9  */\n  0x80a30034, /*2:lwz     r5,52(r3)  */\n  0x39030180,  /* addi    r8,r3,384  */\n  0x39230190,  /* addi    r9,r3,400  */\n  0x70a00fff,  /* andi.   r0,r5,4095 */\n  0x7ca043a6,  /* mtvrsave r5        */\n  0x4d820420,  /* beqctr             */\n  0x7e8040ce,  /* lvx     v20,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7ea048ce,  /* lvx     v21,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7ec040ce,  /* lvx     v22,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7ee048ce,  /* lvx     v23,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7f0040ce,  /* lvx     v24,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7f2048ce,  /* lvx     v25,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7f4040ce,  /* lvx     v26,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7f6048ce,  /* lvx     v27,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7f8040ce,  /* lvx     v28,r0,r8  */\n  0x39080020,  /* addi    r8,r8,32   */\n  0x7fa048ce,  /* lvx     v29,r0,r9  */\n  0x39290020,  /* addi    r9,r9,32   */\n  0x7fc040ce,  /* lvx     v30,r0,r8  */\n  0x7fe048ce,  /* lvx     v31,r0,r9  */\n  #endif\n\n  0x4e800420,  /* bctr */\n};\n\n#if LIBCO_PPCDESC\n  /* function call goes through indirect descriptor */\n  #define CO_SWAP_ASM(x, y) ((void (*)(cothread_t, cothread_t))(uintptr_t)x)(x, y)\n#else\n  /* function call goes directly to code */\n  #define CO_SWAP_ASM(x, y) ((void (*)(cothread_t, cothread_t))(uintptr_t)libco_ppc_code)(x, y)\n#endif\n\nstatic uint32_t* co_create_(unsigned size, uintptr_t entry) {\n  (void)entry;\n\n  uint32_t* t = (uint32_t*)malloc(size);\n\n  #if LIBCO_PPCDESC\n  if(t) {\n    memcpy(t, (void*)entry, sizeof(void*) * 3);  /* copy entry's descriptor */\n    *(const void**)t = libco_ppc_code;  /* set function pointer to swap routine */\n  }\n  #endif\n\n  return t;\n}\n\ncothread_t co_create(unsigned int size, void (*entry_)(void)) {\n  uintptr_t entry = (uintptr_t)entry_;\n  uint32_t* t = 0;\n\n  /* be sure main thread was successfully allocated */\n  if(co_active()) {\n    size += state_size + above_stack + stack_align;\n    t = co_create_(size, entry);\n  }\n\n  if(t) {\n    uintptr_t sp;\n    int shift;\n\n    /* save current registers into new thread, so that any special ones will have proper values when thread is begun */\n    CO_SWAP_ASM(t, t);\n\n    #if LIBCO_PPCDESC\n    entry = (uintptr_t)*(void**)entry;  /* get real address */\n    #endif\n\n    /* put stack near end of block, and align */\n    sp = (uintptr_t)t + size - above_stack;\n    sp -= sp % stack_align;\n\n    /* on PPC32, we save and restore GPRs as 32 bits. for PPC64, we\n       save and restore them as 64 bits, regardless of the size the ABI\n       uses. so, we manually write pointers at the proper size. we always\n       save and restore at the same address, and since PPC is big-endian,\n       we must put the low byte first on PPC32. */\n\n    /* if uintptr_t is 32 bits, >>32 is undefined behavior,\n       so we do two shifts and don't have to care how many bits uintptr_t is. */\n    #if LIBCO_PPC64\n    shift = 16;\n    #else\n    shift = 0;\n    #endif\n\n    /* set up so entry will be called on next swap */\n    t[ 8] = (uint32_t)(entry >> shift >> shift);\n    t[ 9] = (uint32_t)entry;\n\n    t[10] = (uint32_t)(sp >> shift >> shift); \n    t[11] = (uint32_t)sp;\n  }\n\n  return t;\n}\n\nvoid co_delete(cothread_t t) {\n  free(t);\n}\n\nstatic void co_init_(void) {\n  #if LIBCO_MPROTECT\n  long page_size = sysconf(_SC_PAGESIZE);\n  if(page_size > 0) {\n    uintptr_t align = page_size;\n    uintptr_t begin = (uintptr_t)libco_ppc_code;\n    uintptr_t end   = begin + sizeof libco_ppc_code;\n\n    /* align beginning and end */\n    end   += align - 1;\n    end   -= end   % align;\n    begin -= begin % align;\n\n    mprotect((void*)begin, end - begin, PROT_READ | PROT_EXEC);\n  }\n  #endif\n\n  co_active_handle = co_create_(state_size, (uintptr_t)&co_switch);\n}\n\ncothread_t co_active() {\n  if(!co_active_handle) co_init_();\n\n  return co_active_handle;\n}\n\nvoid co_switch(cothread_t t) {\n  cothread_t old = co_active_handle;\n  co_active_handle = t;\n\n  CO_SWAP_ASM(t, old);\n}\n"
  },
  {
    "path": "vault/syn_fiber_sjlj.h",
    "content": "/*\n  libco.sjlj (2008-01-28)\n  author: Nach\n  license: public domain\n*/\n\n/*\n  note this was designed for UNIX systems. Based on ideas expressed in a paper by Ralf Engelschall.\n  for SJLJ on other systems, one would want to rewrite springboard() and co_create() and hack the jmb_buf stack pointer.\n*/\n\n#include <stdlib.h>\n#include <signal.h>\n#include <setjmp.h>\n\ntypedef struct {\n  sigjmp_buf context;\n  void (*coentry)(void);\n  void* stack;\n} cothread_struct;\n\nstatic THREAD cothread_struct co_primary;\nstatic THREAD cothread_struct* creating;\nstatic THREAD cothread_struct* co_running = 0;\n\nstatic void springboard(int ignored) {\n  if(sigsetjmp(creating->context, 0)) {\n    co_running->coentry();\n  }\n}\n\ncothread_t co_active() {\n  if(!co_running) co_running = &co_primary;\n  return (cothread_t)co_running;\n}\n\ncothread_t co_create(unsigned int size, void (*coentry)(void)) {\n  if(!co_running) co_running = &co_primary;\n\n  cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));\n  if(thread) {\n    struct sigaction handler;\n    struct sigaction old_handler;\n\n    stack_t stack;\n    stack_t old_stack;\n\n    thread->coentry = thread->stack = 0;\n\n    stack.ss_flags = 0;\n    stack.ss_size = size;\n    thread->stack = stack.ss_sp = malloc(size);\n    if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {\n      handler.sa_handler = springboard;\n      handler.sa_flags = SA_ONSTACK;\n      sigemptyset(&handler.sa_mask);\n      creating = thread;\n\n      if(!sigaction(SIGUSR1, &handler, &old_handler)) {\n        if(!raise(SIGUSR1)) {\n          thread->coentry = coentry;\n        }\n        sigaltstack(&old_stack, 0);\n        sigaction(SIGUSR1, &old_handler, 0);\n      }\n    }\n\n    if(thread->coentry != coentry) {\n      co_delete(thread);\n      thread = 0;\n    }\n  }\n\n  return (cothread_t)thread;\n}\n\nvoid co_delete(cothread_t cothread) {\n  if(cothread) {\n    if(((cothread_struct*)cothread)->stack) {\n      free(((cothread_struct*)cothread)->stack);\n    }\n    free(cothread);\n  }\n}\n\nvoid co_switch(cothread_t cothread) {\n  if(!sigsetjmp(co_running->context, 0)) {\n    co_running = (cothread_struct*)cothread;\n    siglongjmp(co_running->context, 1);\n  }\n}\n"
  },
  {
    "path": "vault/syn_fiber_ucontext.h",
    "content": "/*\n  libco.ucontext (2008-01-28)\n  author: Nach\n  license: public domain\n*/\n\n/*\n  WARNING: the overhead of POSIX ucontext is very high,\n  assembly versions of libco or libco_sjlj should be much faster\n\n  this library only exists for two reasons:\n  1: as an initial test for the viability of a ucontext implementation\n  2: to demonstrate the power and speed of libco over existing implementations,\n     such as pth (which defaults to wrapping ucontext on unix targets)\n\n  use this library only as a *last resort*\n*/\n\n#define _BSD_SOURCE\n#include <stdlib.h>\n#include <ucontext.h>\n\nstatic THREAD ucontext_t co_primary;\nstatic THREAD ucontext_t* co_running = 0;\n\ncothread_t co_active() {\n  if(!co_running) co_running = &co_primary;\n  return (cothread_t)co_running;\n}\n\ncothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {\n  if(!co_running) co_running = &co_primary;\n  ucontext_t* thread = (ucontext_t*)malloc(sizeof(ucontext_t));\n  if(thread) {\n    if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize))) {\n      thread->uc_link = co_running;\n      thread->uc_stack.ss_size = heapsize;\n      makecontext(thread, coentry, 0);\n    } else {\n      co_delete((cothread_t)thread);\n      thread = 0;\n    }\n  }\n  return (cothread_t)thread;\n}\n\nvoid co_delete(cothread_t cothread) {\n  if(cothread) {\n    if(((ucontext_t*)cothread)->uc_stack.ss_sp) { free(((ucontext_t*)cothread)->uc_stack.ss_sp); }\n    free(cothread);\n  }\n}\n\nvoid co_switch(cothread_t cothread) {\n  ucontext_t* old_thread = co_running;\n  co_running = (ucontext_t*)cothread;\n  swapcontext(old_thread, co_running);\n}\n"
  },
  {
    "path": "vault/syn_fiber_win32.h",
    "content": "/*\n  libco.win (2008-01-28)\n  authors: Nach, byuu\n  license: public domain\n*/\n\n#ifndef WINVER\n#define WINVER 0x0400\n#endif\n#ifndef _WIN32_WINNT\n#define _WIN32_WINNT 0x0400\n#endif\n#include <windows.h>\n\nstatic THREAD cothread_t co_active_ = 0;\n\nstatic void __stdcall co_thunk(void* coentry) {\n  ((void (*)(void))coentry)();\n}\n\ncothread_t co_active() {\n  if(!co_active_) {\n    ConvertThreadToFiber(0);\n    co_active_ = GetCurrentFiber();\n  }\n  return co_active_;\n}\n\ncothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {\n  if(!co_active_) {\n    ConvertThreadToFiber(0);\n    co_active_ = GetCurrentFiber();\n  }\n  return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);\n}\n\nvoid co_delete(cothread_t cothread) {\n  DeleteFiber(cothread);\n}\n\nvoid co_switch(cothread_t cothread) {\n  co_active_ = cothread;\n  SwitchToFiber(cothread);\n}\n"
  },
  {
    "path": "vault/syn_fiber_x86.h",
    "content": "/*\n  libco.x86 (2016-09-14)\n  author: byuu\n  license: public domain\n*/\n\n#include <assert.h>\n#include <stdlib.h>\n\n#if defined(__clang__) || defined(__GNUC__)\n  #define fastcall __attribute__((fastcall))\n#elif defined(_MSC_VER)\n  #define fastcall __fastcall\n#else\n  #error \"libco: please define fastcall macro\"\n#endif\n\nstatic THREAD long co_active_buffer[64];\nstatic THREAD cothread_t co_active_handle = 0;\nstatic void (fastcall *co_swap)(cothread_t, cothread_t) = 0;\n\n#ifdef LIBCO_MPROTECT\n  ALIGNAS(4096)\n#else\n  SECTION(text)\n#endif\n/* ABI: fastcall */\nstatic const unsigned char co_swap_function[4096] = {\n  0x89, 0x22,        /* mov [edx],esp    */\n  0x8b, 0x21,        /* mov esp,[ecx]    */\n  0x58,              /* pop eax          */\n  0x89, 0x6a, 0x04,  /* mov [edx+ 4],ebp */\n  0x89, 0x72, 0x08,  /* mov [edx+ 8],esi */\n  0x89, 0x7a, 0x0c,  /* mov [edx+12],edi */\n  0x89, 0x5a, 0x10,  /* mov [edx+16],ebx */\n  0x8b, 0x69, 0x04,  /* mov ebp,[ecx+ 4] */\n  0x8b, 0x71, 0x08,  /* mov esi,[ecx+ 8] */\n  0x8b, 0x79, 0x0c,  /* mov edi,[ecx+12] */\n  0x8b, 0x59, 0x10,  /* mov ebx,[ecx+16] */\n  0xff, 0xe0,        /* jmp eax          */\n};\n\n#ifdef _WIN32\n  #include <windows.h>\n\n  static void co_init() {\n    #ifdef LIBCO_MPROTECT\n    DWORD old_privileges;\n    VirtualProtect((void*)co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READ, &old_privileges);\n    #endif\n  }\n#else\n  #include <unistd.h>\n  #include <sys/mman.h>\n\n  static void co_init() {\n    #ifdef LIBCO_MPROTECT\n    unsigned long addr = (unsigned long)co_swap_function;\n    unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));\n    unsigned long size = (addr - base) + sizeof co_swap_function;\n    mprotect((void*)base, size, PROT_READ | PROT_EXEC);\n    #endif\n  }\n#endif\n\nstatic void crash() {\n  assert(0);  /* called only if cothread_t entrypoint returns */\n}\n\ncothread_t co_active() {\n  if(!co_active_handle) co_active_handle = &co_active_buffer;\n  return co_active_handle;\n}\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void)) {\n  cothread_t handle;\n  if(!co_swap) {\n    co_init();\n    co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;\n  }\n  if(!co_active_handle) co_active_handle = &co_active_buffer;\n  size += 256;  /* allocate additional space for storage */\n  size &= ~15;  /* align stack to 16-byte boundary */\n\n  if(handle = (cothread_t)malloc(size)) {\n    long *p = (long*)((char*)handle + size);  /* seek to top of stack */\n    *--p = (long)crash;                       /* crash if entrypoint returns */\n    *--p = (long)entrypoint;                  /* start of function */\n    *(long*)handle = (long)p;                 /* stack pointer */\n  }\n\n  return handle;\n}\n\nvoid co_delete(cothread_t handle) {\n  free(handle);\n}\n\nvoid co_switch(cothread_t handle) {\n  register cothread_t co_previous_handle = co_active_handle;\n  co_swap(co_active_handle = handle, co_previous_handle);\n}\n"
  },
  {
    "path": "vault/syn_mcmp.c",
    "content": "// # lockfree queues (multiple consumer-multiple producer) #####################\n// License: WTFPL. https://github.com/darkautism/lfqueue\n// Use -O0 flag to compile (needed?).\n\n#ifndef MCMP_H\n#define MCMP_H\n\nstruct mcmp;\n\nint   mcmp_new(struct mcmp *ctx);\nint   mcmp_del(struct mcmp *ctx);\nint   mcmp_add(struct mcmp *ctx, void *data);\nvoid *mcmp_pop(struct mcmp *ctx );\n\n#endif\n\n#ifdef MCMP_C\n#pragma once\n//#include \"../memory/memory_realloc.c\"\n//#include \"async_atomic.c\"\n#include <stdlib.h> \n#include <string.h>\n#include <errno.h>\n\nstruct mcmp_node {\n    void * data;\n    struct mcmp_node *next;\n};\n\nstruct mcmp {\n    struct mcmp_node *head;\n    struct mcmp_node *tail;\n    size_t count; // int\n};\n\nint mcmp_new(struct mcmp *ctx) {\n    struct mcmp_node * tmpnode = memset( (char*)REALLOC(0,sizeof(struct mcmp_node)), 0, sizeof(struct mcmp_node));\n    if (!tmpnode) \n        return -errno;\n    \n    memset(ctx,0,sizeof(struct mcmp));\n    ctx->head=ctx->tail=tmpnode;\n    return 0;\n}\n\nint mcmp_del(struct mcmp *ctx){\n    if ( ctx->tail && ctx->head ) { // if have data in queue\n        struct mcmp_node * walker = ctx->head, *tmp;\n        while ( walker != ctx->tail ) { // while still have node\n            tmp = walker->next;\n            REALLOC(walker, 0);\n            walker=tmp;\n        }\n        REALLOC(ctx->head, 0); // free the empty node\n        memset(ctx,0,sizeof(struct mcmp));\n    }\n    return 0;\n}\n\nint mcmp_add(struct mcmp *ctx, void * data) {\n    struct mcmp_node * p;\n    struct mcmp_node * tmpnode = memset( (char*)REALLOC(0,sizeof(struct mcmp_node)), 0, sizeof(struct mcmp_node));\n    if (!tmpnode)\n        return -errno;\n    \n    tmpnode->data=data;\n    do {\n        p = ctx->tail;\n        if ( __sync_bool_compare_and_swap(&ctx->tail,p,tmpnode)) {\n            p->next=tmpnode;\n            break;  \n        }\n    } while(1);\n    __sync_add_and_fetch( &ctx->count, 1);\n    return 0;\n}\n\nvoid * mcmp_pop(struct mcmp *ctx ) {\n    void * ret=0;\n    struct mcmp_node * p;\n    do {\n        p = ctx->head;\n    } while(p==0 || !__sync_bool_compare_and_swap(&ctx->head,p,0));\n    \n    if( p->next==0) {\n        ctx->head=p;\n        return 0;\n    }\n    ret=p->next->data;\n    ctx->head=p->next;\n    __sync_add_and_fetch( &ctx->count, -1);\n    REALLOC(p, 0);\n    return ret;\n}\n\n#ifdef MCMP_DEMO\n#include <stdio.h>\n#include <stdlib.h>\nint main() {\n    long ret;\n    struct mcmp ctx;\n    mcmp_new(&ctx);\n    mcmp_add(&ctx,(void *)1);\n    mcmp_add(&ctx,(void *)3);\n    mcmp_add(&ctx,(void *)5);\n    mcmp_add(&ctx,(void *)8);\n    mcmp_add(&ctx,(void *)4);\n    mcmp_add(&ctx,(void *)6);\n\n    while ( (ret = *(int*)mcmp_pop(&ctx)) != 0 )\n        printf(\"lfq_dequeue %ld\\n\", ret);\n\n    mcmp_del(&ctx);\n}\n#define main main__\n#endif // MCMP_DEMO\n#endif // MCMP_C\n"
  },
  {
    "path": "vault/syn_mutex.c",
    "content": "// # mutexes ###################################################################\n// - rlyeh, public domain\n\n#ifndef MUTEX_H\n#define MUTEX_H\n#include <stdbool.h>\n\ntypedef union mutex mutex;\n\nvoid mutex_new(mutex *m);\nvoid mutex_del(mutex *m);\nbool mutex_trylock(mutex *m);\nvoid mutex_acquire(mutex *m);\nvoid mutex_release(mutex *m);\n\n#endif\n\n#ifdef MUTEX_C\n#pragma once\n\nunion mutex {\n    char opaque_win_x64[40];\n    char opaque_cpp_x64_vs2015[8];\n    char opaque_cpp_x64_vs2017[80];\n    char opaque_cpp_x32_vs2017[48];\n};\n\n#if defined(__cplusplus)\n#   include <mutex>\n#   define MUTEX_API                \"cpp\"\n#   define mutex_t                  std::recursive_mutex\n#   define mutex_initial_(mutex)    (new (mutex) mutex_t)\n#   define mutex_trylock_(mutex)    ((mutex)->try_lock())\n#   define mutex_acquire_(mutex)    ((mutex)->lock())\n#   define mutex_release_(mutex)    ((mutex)->unlock())\n#   define mutex_destroy_(mutex)    ((mutex)->~recursive_mutex())\n#elif defined(_WIN32)\n//#   include <winsock2.h>\n#   define MUTEX_API                \"win\"\n#   define mutex_t                  CRITICAL_SECTION\n#   define mutex_initial_(mutex)    (InitializeCriticalSection(mutex))\n#   define mutex_trylock_(mutex)    (TryEnterCriticalSection(mutex))\n#   define mutex_acquire_(mutex)    (EnterCriticalSection(mutex))\n#   define mutex_release_(mutex)    (LeaveCriticalSection(mutex))\n#   define mutex_destroy_(mutex)    (DeleteCriticalSection(mutex))\n#else\n#   define _GNU_SOURCE\n#   include <pthread.h>\n#   define MUTEX_API                \"pth\"\n#   define mutex_t                  pthread_mutex_t\n//# define mutex_initial_(mutex)    (pthread_mutex_init(mutex, NULL)\n#   define mutex_trylock_(mutex)    (pthread_mutex_trylock(mutex))\n#   define mutex_acquire_(mutex)    (pthread_mutex_lock(mutex))\n#   define mutex_release_(mutex)    (pthread_mutex_unlock(mutex))\n#   define mutex_destroy_(mutex)    (pthread_mutex_destroy(mutex))\nstatic void mutex_initial_(pthread_mutex_t *mutex) {\n    pthread_mutexattr_t attr;\n    pthread_mutexattr_init(&attr);\n    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\n    pthread_mutex_init(mutex, &attr);\n    pthread_mutexattr_destroy(&attr);\n}\n#endif\n\ntypedef int mtx_is_large_enough[ sizeof(mutex) >= sizeof(mutex_t) ];\n\nconst char *mutex_api = MUTEX_API;\n\nvoid mutex_new(mutex *m) {\n    mutex v = {0}; *m = v;\n    mutex_initial_((mutex_t*)m);\n}\nvoid mutex_del(mutex *m) {\n    mutex_destroy_((mutex_t*)m);\n}\nbool mutex_trylock(mutex *m) {\n    return !!mutex_trylock_((mutex_t*)m);\n}\nvoid mutex_acquire(mutex *m) {\n    mutex_acquire_((mutex_t*)m);\n}\nvoid mutex_release(mutex *m) {\n    mutex_release_((mutex_t*)m);\n}\n\n#endif\n\n#if MUTEX_BENCH\n#include <omp.h>\n#include <stdio.h>\nint main() {\n    enum { N = 100, M = 1000 * 1000 };\n    double t = omp_get_wtime();\n    mutex m = {0};\n    mutex_new(&m);\n    for( int i = 0; i < N*M; ++i ) {\n        mutex_acquire(&m);\n        mutex_release(&m);\n    }\n    mutex_del(&m);\n    t = omp_get_wtime() - t;\n    printf(\"%5.2fs %6.2fM ops/s (api: %s)\\n\", t, ((2*N*M+2)/t) / M, mutex_api );\n}\n// 2.87s  69.63M ops/s (api: cpp)\n// 2.03s  98.59M ops/s (api: win)\n#endif\n\n#if MUTEX_DEMO\n#include <stdio.h>\n#include <assert.h>\nint main() {\n    mutex m = {0};\n    mutex_new(&m);\n\n    mutex_acquire(&m);\n    mutex_release(&m);\n    assert( mutex_trylock(&m) );\n    assert( mutex_trylock(&m) );\n    mutex_release(&m);\n    assert( puts(\"ok\") >= 0 );\n}\n#endif\n"
  },
  {
    "path": "vault/syn_semaphore.c",
    "content": "// # semaphores ################################################################\n// combination of mutex+condvar. used to perform operations on shared data.\n// - rlyeh, public domain.\n\n#ifndef SEMAPHORE_H\n#define SEMAPHORE_H\n\ntypedef struct semaphore semaphore;\n\nvoid semaphore_init( semaphore *s );\nvoid semaphore_wait( semaphore *s );\nvoid semaphore_emit( semaphore *s );\nvoid semaphore_quit( semaphore *s );\n\n#endif\n\n#ifdef SEMAPHORE_C\n#pragma once\n//#include \"async_condv.c\"\n//#include \"async_mutex.c\"\n\nstruct semaphore {\n    mutex mtx;\n    condv cnd;\n    int alarm;\n};\n\nvoid semaphore_init( semaphore *s ) {\n    semaphore v = {0}; *s = v;\n    mutex_new( &s->mtx );\n    condv_init( &s->cnd );\n}\nvoid semaphore_wait( semaphore *s ) {\n    mutex_acquire( &s->mtx );\n    while( !s->alarm ) {\n        condv_wait(&s->cnd, &s->mtx, 0);\n    }\n    s->alarm = 0;\n    mutex_release(&s->mtx);\n}\nvoid semaphore_emit( semaphore *s ) {\n    mutex_acquire(&s->mtx);\n    s->alarm = 1;\n    mutex_release(&s->mtx);\n    condv_emit(&s->cnd);\n}\nvoid semaphore_quit( semaphore *s ) {\n    condv_quit( &s->cnd );\n    mutex_del( &s->mtx );\n    semaphore v = {0}; *s = v;\n}\n\n#endif\n\n#if SEMAPHORE_DEMO\n#include <assert.h>\n#include <stdio.h>\nint main() {\n    semaphore s = {0};\n    semaphore_init(&s);\n    semaphore_emit(&s);\n    semaphore_quit(&s);\n    assert( puts(\"ok\") >= 0 );\n}\n#endif\n"
  },
  {
    "path": "vault/syn_sleep.c",
    "content": "// # sleep functions ###########################################################\n// - rlyeh, public domain\n\n#ifndef SLEEP_H\n#define SLEEP_H\n\nvoid sleep_ns( double ns );\nvoid sleep_us( double us );\nvoid sleep_ms( double ms );\nvoid sleep_ss( double ss );\n\n#endif\n\n#ifdef SLEEP_C\n#pragma once\n#ifdef _WIN32\n//#include <winsock2.h>\n#else\n#include <time.h>\n#endif\n\nvoid sleep_ns( double ns ) {\n    if( ns > 0 ) {\n#ifdef _WIN32\n        LARGE_INTEGER li;      // Windows sleep in 100ns units\n        HANDLE timer = CreateWaitableTimer(NULL, TRUE, NULL);\n        li.QuadPart = (LONGLONG)(__int64)(-ns/100); // Negative for relative time\n        SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE);\n        WaitForSingleObject(timer, INFINITE);\n        CloseHandle(timer);\n#else\n        struct timespec wait = {0};\n        wait.tv_sec = ns / 1e9;\n        wait.tv_nsec = ns - wait.tv_sec * 1e9;\n        nanosleep(&wait, NULL);\n#endif\n    }\n}\nvoid sleep_us( double us ) {\n    sleep_ns(us * 1e3);\n}\nvoid sleep_ms( double ms ) {\n    sleep_ns(ms * 1e6);\n}\nvoid sleep_ss( double ss ) {\n    sleep_ns(ss * 1e9);\n}\n\n#endif\n"
  },
  {
    "path": "vault/syn_thread.c",
    "content": "// # threads ###################################################################\n// - rlyeh, public domain\n//\n// [ref] http://bisqwit.iki.fi/story/howto/openmp/\n// [ref] https://github.com/tinycthread/tinycthread/\n// [ref] https://stackoverflow.com/questions/12744324/how-to-detach-a-thread-on-windows-c#answer-12746081\n// todo: affinities\n\n#ifndef THREAD_H\n#define THREAD_H\n#include <stdbool.h>\n#include <stdint.h>\n\nuint64_t thread_self();\nvoid thread_yield();\nbool detach( void (*func)(void *), void *arg );\nbool thread(int thread_id, void (*func)(void *), void *arg);\nbool join(int thread_id);\n\n#endif\n\n#ifdef THREAD_C\n#pragma once\n//#include \"c_ifdef.c\"\n//#include \"async_tls.c\"\n\n#include <stdint.h>\n#include <stdbool.h>\n#ifdef _WIN32\n//#   include <winsock2.h>\n#   include <windows.h>  // SwitchToThread()\n#   include <process.h>  // _getpid()\n#   define THREAD_API \"win\"\n#else\n#   include <pthread.h>\n#   include <sched.h>    // sched_yield()\n#   include <sys/time.h> // timespec\n#   include <time.h>     // nanosleep()\n#   include <unistd.h>   // getpid()\n#   if __linux__\n#   include <sys/syscall.h>\n#   endif\n#   define THREAD_API \"pth\"\n#endif\n#if defined(__cplusplus)\n#   include <thread>\n#   undef  THREAD_API\n#   define THREAD_API \"cpp\"\n#endif\n\n#ifndef THREAD_MAX\n#define THREAD_MAX 1024\n#endif \n\nconst char *thdapi = THREAD_API;\n\nuint64_t thread_self() {\n    IFDEF(IOS,     return (mach_port_t)pthread_mach_thread_np( pthread_self() ) );\n    IFDEF(OSX,     return (mach_port_t)pthread_mach_thread_np( pthread_self() ) );\n    IFDEF(LINUX,   return (uint64_t)syscall(SYS_gettid) );\n    IFDEF(WINDOWS, return GetCurrentThreadId() );\n    IFDEF(ANDROID, return pthread_self() );\n    // fallback\n    static __thread int id;\n    return (intptr_t)&id;\n}\n\nvoid thread_yield() {\n    IFDEF(CPP, std::this_thread::yield(),\n        IFDEF(WINDOWS, SwitchToThread(), // also, YieldProcessor(); Sleep(0); SleepEx(0, FALSE); _mm_pause();\n            pthread_yield()       // also, sched_yield(); __asm__ __volatile__(\"pause\" ::: \"memory\"); nanosleep();\n        );\n    );\n}\n\n#if defined(__cplusplus)\n    static std::thread threads[THREAD_MAX];\n    bool detach( void (*func)(void *), void *arg ) {\n        return std::thread( [=]{ tls_init(); func(arg); tls_quit(); }).detach(), true;\n    }\n    bool thread(int thread_id, void (*func)(void *), void *arg) {\n        return threads[thread_id] = std::thread( [&]{ tls_init(); func(arg); tls_quit(); } ), true;\n    }\n    bool join(int thread_id) {\n        return threads[thread_id].join(), true;\n    }\n#else\n    static void *threads[THREAD_MAX];\n    typedef struct thread_args {\n        void *func;\n        void *args;\n    } thread_args;\n    #ifdef _WIN32\n    static DWORD WINAPI thread_wrapper(LPVOID opaque) {\n    #else\n    static void *thread_wrapper( void *opaque ) {\n    #endif\n        void (*func)(void *) = ((thread_args *)opaque)->func;\n        void *arg0 = ((thread_args *)opaque)->args;\n        REALLOC( opaque, 0 );\n        tls_init();\n        func( arg0 );\n        tls_quit();\n        IFNDEF(WINDOWS, pthread_exit((void**)0) );\n        return 0;\n    }\n    static void* launch( void (*func)(void *), void *args ) {\n        thread_args *ta = (struct thread_args*)REALLOC( 0, sizeof(struct thread_args));\n        ta->func = func;\n        ta->args = args;\n        IFDEF(WINDOWS, {\n            return CreateThread(NULL, 0, thread_wrapper, (LPVOID)ta, 0, NULL);\n        }, {\n            void *ret;\n            if( pthread_create(&ret, NULL, thread_wrapper, (void *)ta) != 0 ) {\n                *ret = 0;\n            }\n            return ret;\n        });\n    }\n    bool detach( void (*func)(void *), void *arg ) {\n        void *thr = launch(func, arg);\n        IFDEF(WINDOWS, return CloseHandle(thr) != 0 ? true : false,\n            return pthread_detach(thr) == 0 ? true : false );\n    }\n    bool thread(int thread_id, void (*func)(void *), void *arg) {\n        return !!(threads[thread_id] = launch(func, arg));\n    }\n    bool join(int thread_id) {\n        IFDEF(WINDOWS, {\n            if( WaitForSingleObject(threads[thread_id], INFINITE) != WAIT_FAILED ) {\n                return (CloseHandle(threads[thread_id]), true);\n            }\n            return false;\n        }, {\n            void *nil;\n            int err;\n            do {\n                err = pthread_join(threads[thread_id], &nil );\n            } while( err == EINTR );\n            return err == 0;\n        } );\n    }\n#endif\n\n#endif\n\n#if THREAD_DEMO\n#include <omp.h>\n#include <stdio.h>\nint writes = 0;\nint N = 1024, M = 1024 * 1024;\nvoid write( void *arg ) {\n    for( int j = 0; j < M; ++j ) ++writes;\n}\nint main() {\n    double t = omp_get_wtime();\n    for( int id = 0; id < N; ++id ) {\n        thread( id, write, &writes );\n    }\n    for( int id = 0; id < N; ++id ) {\n        join( id );\n    }\n    t = omp_get_wtime() - t;\n    printf(\"%5.2fs %6.2fM ops/s\\n\", t, ((N*M)/t) / M );\n    printf(\"thread-id %lld, %5.2f%% concurrent-writes found\\n\", thread_self(), (writes*100.) / (N*M));\n}\n#endif\n"
  },
  {
    "path": "vault/syn_tls.c",
    "content": "// # thread-local storage ######################################################\n// - rlyeh, public domain.\n\n#ifndef TLS_H\n#define TLS_H\n\nvoid tls_add_init( void (*func)(void *arg), void *arg );\nvoid tls_add_quit( void (*func)(void *arg), void *arg );\nvoid tls_init();\nvoid tls_quit();\n\n#endif\n\n#ifdef TLS_C\n#pragma once\n\nstatic struct tls {\n    void (*funs[256])( void *arg );\n    void *args[256];\n    int count;\n} inits = {0}, quits = {0};\n\nvoid tls_add_init( void (*func)(void *arg), void *arg ) {\n    int with = inits.count++;\n    inits.funs[ with ] = func;\n    inits.args[ with ] = arg;\n}\nvoid tls_add_quit( void (*func)(void *arg), void *arg ) {\n    int with = quits.count++;\n    quits.funs[ with ] = func;\n    quits.args[ with ] = arg;\n}\nvoid tls_init() {\n    for( int i = 0; i < inits.count; ++i ) {\n        inits.funs[i]( inits.args[i] );\n    }\n}\nvoid tls_quit() {\n    for( int i = inits.count; i-- > 0; ) {\n        quits.funs[i]( quits.args[i] );\n    }\n}\n\n/*\nvoid tlspush(void*);\nvoid*tlspop();\n\n__thread any argstack[32] = {0};\n__thread void **argptr = argstack;\nvoid tlspush(void *arg) {\n    *argptr++ = arg;\n}\nvoid*tlspop() {\n    return *(--argptr);\n}\n*/\n\n#endif\n\n#if TLS_DEMO\n#include <stdio.h>\n#include \"async_thread.c\"\n#include \"async_sleep.c\"\n\nvoid myinit1(void *arg) { puts(\"hi1!\"); }\nvoid myinit2(void *arg) { puts(\"hi2!\"); }\nvoid myquit2(void *arg) { puts(\"bye2!\"); }\nvoid myquit1(void *arg) { puts(\"bye1!\"); }\n\nvoid hello(void *arg) { puts(\"hello\"); }\n\nint main() {\n    tls_add_init( myinit1, 0 );\n    tls_add_quit( myquit1, 0 );\n    tls_add_init( myinit2, 0 );\n    tls_add_quit( myquit2, 0 );\n\n    detach( hello, 0 );\n    sleep_ss(1);\n\n    thread( 10, hello, 0 );\n    join(10);\n}\n\n#endif\n"
  }
]