damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 389c2c96953e6f36ad1852264692ee5124e51edb
parent 4a6121ba1334466dcf868b62034da3d04990ba83
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 25 Jan 2024 14:23:36 -0800

nostrdb: add supporting files before the move commit

Diffstat:
Anostrdb/bech32.c | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anostrdb/bech32.h | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mnostrdb/compiler.h | 342+++++++++++++------------------------------------------------------------------
Mnostrdb/cursor.h | 60++++++++++++------------------------------------------------
4 files changed, 426 insertions(+), 335 deletions(-)

diff --git a/nostrdb/bech32.c b/nostrdb/bech32.c @@ -0,0 +1,217 @@ +/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.c, + * with only the two ' > 90' checks hoisted, and more internals exposed */ + +/* Copyright (c) 2017, 2021 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "config.h" +#include <assert.h> +#include "bech32.h" +#include <string.h> + +static uint32_t bech32_polymod_step(uint32_t pre) { + uint8_t b = pre >> 25; + return ((pre & 0x1FFFFFF) << 5) ^ + (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ + (-((b >> 1) & 1) & 0x26508e6dUL) ^ + (-((b >> 2) & 1) & 0x1ea119faUL) ^ + (-((b >> 3) & 1) & 0x3d4233ddUL) ^ + (-((b >> 4) & 1) & 0x2a1462b3UL); +} + +static uint32_t bech32_final_constant(bech32_encoding enc) { + if (enc == BECH32_ENCODING_BECH32) return 1; + if (enc == BECH32_ENCODING_BECH32M) return 0x2bc830a3; + assert(0); +} + +const char bech32_charset[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +const int8_t bech32_charset_rev[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 +}; + +int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len, bech32_encoding enc) { + uint32_t chk = 1; + size_t i = 0; + while (hrp[i] != 0) { + int ch = hrp[i]; + if (ch < 33 || ch > 126) { + return 0; + } + + if (ch >= 'A' && ch <= 'Z') return 0; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + ++i; + } + if (i + 7 + data_len > max_input_len) return 0; + chk = bech32_polymod_step(chk); + while (*hrp != 0) { + chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); + *(output++) = *(hrp++); + } + *(output++) = '1'; + for (i = 0; i < data_len; ++i) { + if (*data >> 5) return 0; + chk = bech32_polymod_step(chk) ^ (*data); + *(output++) = bech32_charset[*(data++)]; + } + for (i = 0; i < 6; ++i) { + chk = bech32_polymod_step(chk); + } + chk ^= bech32_final_constant(enc); + for (i = 0; i < 6; ++i) { + *(output++) = bech32_charset[(chk >> ((5 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; +} + +bech32_encoding bech32_decode_len(char* hrp, uint8_t *data, size_t *data_len, const char *input, size_t input_len) { + uint32_t chk = 1; + size_t i; + size_t hrp_len; + int have_lower = 0, have_upper = 0; + if (input_len < 8) { + return BECH32_ENCODING_NONE; + } + *data_len = 0; + while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if (1 + *data_len >= input_len || *data_len < 6) { + return BECH32_ENCODING_NONE; + } + *(data_len) -= 6; + for (i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if (ch < 33 || ch > 126) { + return BECH32_ENCODING_NONE; + } + if (ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if (ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; + } + hrp[i] = ch; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + } + hrp[i] = 0; + chk = bech32_polymod_step(chk); + for (i = 0; i < hrp_len; ++i) { + chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); + } + ++i; + while (i < input_len) { + int v = (input[i] & 0x80) ? -1 : bech32_charset_rev[(int)input[i]]; + if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; + if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; + if (v == -1) { + return BECH32_ENCODING_NONE; + } + chk = bech32_polymod_step(chk) ^ v; + if (i + 6 < input_len) { + data[i - (1 + hrp_len)] = v; + } + ++i; + } + if (have_lower && have_upper) { + return BECH32_ENCODING_NONE; + } + if (chk == bech32_final_constant(BECH32_ENCODING_BECH32)) { + return BECH32_ENCODING_BECH32; + } else if (chk == bech32_final_constant(BECH32_ENCODING_BECH32M)) { + return BECH32_ENCODING_BECH32M; + } else { + return BECH32_ENCODING_NONE; + } +} + +bech32_encoding bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, size_t max_input_len) { + size_t len = strlen(input); + if (len > max_input_len) { + return BECH32_ENCODING_NONE; + } + return bech32_decode_len(hrp, data, data_len, input, len); +} + +int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; + } + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; +} + +int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { + uint8_t data[65]; + size_t datalen = 0; + bech32_encoding enc = BECH32_ENCODING_BECH32; + if (witver > 16) return 0; + if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0; + if (witprog_len < 2 || witprog_len > 40) return 0; + if (witver > 0) enc = BECH32_ENCODING_BECH32M; + data[0] = witver; + bech32_convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); + ++datalen; + return bech32_encode(output, hrp, data, datalen, 90, enc); +} + +int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { + uint8_t data[84]; + char hrp_actual[84]; + size_t data_len; + bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr, 90); + if (enc == BECH32_ENCODING_NONE) return 0; + if (data_len == 0 || data_len > 65) return 0; + if (strncmp(hrp, hrp_actual, 84) != 0) return 0; + if (data[0] > 16) return 0; + if (data[0] == 0 && enc != BECH32_ENCODING_BECH32) return 0; + if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M) return 0; + *witdata_len = 0; + if (!bech32_convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0; + if (*witdata_len < 2 || *witdata_len > 40) return 0; + if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0; + *witver = data[0]; + return 1; +} diff --git a/nostrdb/bech32.h b/nostrdb/bech32.h @@ -0,0 +1,142 @@ +/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.h, + * with only the two ' > 90' checks hoisted */ + +/* Copyright (c) 2017, 2021 Pieter Wuille + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef LIGHTNING_COMMON_BECH32_H +#define LIGHTNING_COMMON_BECH32_H +#include "config.h" + +#include <stdint.h> +#include <stdlib.h> + +/** Encode a SegWit address + * + * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be + * updated to contain the null-terminated address. + * In: hrp: Pointer to the null-terminated human readable part to use + * (chain/network specific). + * ver: Version of the witness program (between 0 and 16 inclusive). + * prog: Data bytes for the witness program (between 2 and 40 bytes). + * prog_len: Number of data bytes in prog. + * Returns 1 if successful. + */ +int segwit_addr_encode( + char *output, + const char *hrp, + int ver, + const uint8_t *prog, + size_t prog_len +); + +/** Decode a SegWit address + * + * Out: ver: Pointer to an int that will be updated to contain the witness + * program version (between 0 and 16 inclusive). + * prog: Pointer to a buffer of size 40 that will be updated to + * contain the witness program bytes. + * prog_len: Pointer to a size_t that will be updated to contain the length + * of bytes in prog. + * hrp: Pointer to the null-terminated human readable part that is + * expected (chain/network specific). + * addr: Pointer to the null-terminated address. + * Returns 1 if successful. + */ +int segwit_addr_decode( + int* ver, + uint8_t* prog, + size_t* prog_len, + const char* hrp, + const char* addr +); + +/** Supported encodings. */ +typedef enum { + BECH32_ENCODING_NONE, + BECH32_ENCODING_BECH32, + BECH32_ENCODING_BECH32M +} bech32_encoding; + +/** Encode a Bech32 or Bech32m string + * + * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that + * will be updated to contain the null-terminated Bech32 string. + * In: hrp : Pointer to the null-terminated human readable part. + * data : Pointer to an array of 5-bit values. + * data_len: Length of the data array. + * max_input_len: Maximum valid length of input (90 for segwit usage). + * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). + * Returns 1 if successful. + */ +int bech32_encode( + char *output, + const char *hrp, + const uint8_t *data, + size_t data_len, + size_t max_input_len, + bech32_encoding enc +); + +/** Decode a Bech32 or Bech32m string + * + * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be + * updated to contain the null-terminated human readable part. + * data: Pointer to a buffer of size strlen(input) - 8 that will + * hold the encoded 5-bit data values. + * data_len: Pointer to a size_t that will be updated to be the number + * of entries in data. + * In: input: Pointer to a null-terminated Bech32 string. + * max_input_len: Maximum valid length of input (90 for segwit usage). + * Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful + * with the specified encoding standard. BECH32_ENCODING_NONE is returned if + * decoding failed. + */ +bech32_encoding bech32_decode( + char *hrp, + uint8_t *data, + size_t *data_len, + const char *input, + size_t max_input_len +); + +bech32_encoding bech32_decode_len( + char *hrp, + uint8_t *data, + size_t *data_len, + const char *input, + size_t input_len +); + +/* Helper from bech32: translates inbits-bit bytes to outbits-bit bytes. + * @outlen is incremented as bytes are added. + * @pad is true if we're to pad, otherwise truncate last byte if necessary + */ +int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits, + const uint8_t* in, size_t inlen, int inbits, + int pad); + +/* The charset, and reverse mapping */ +extern const char bech32_charset[32]; +extern const int8_t bech32_charset_rev[128]; + +#endif /* LIGHTNING_COMMON_BECH32_H */ + diff --git a/nostrdb/compiler.h b/nostrdb/compiler.h @@ -1,317 +1,85 @@ -/* CC0 (Public domain) - see LICENSE file for details */ -#ifndef CCAN_COMPILER_H -#define CCAN_COMPILER_H -#include "config.h" -#ifndef COLD -#if HAVE_ATTRIBUTE_COLD -/** - * COLD - a function is unlikely to be called. - * - * Used to mark an unlikely code path and optimize appropriately. - * It is usually used on logging or error routines. - * - * Example: - * static void COLD moan(const char *reason) - * { - * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); - * } - */ -#define COLD __attribute__((__cold__)) -#else -#define COLD -#endif -#endif +#ifndef COMPILER_H +#define COMPILER_H -#ifndef NORETURN -#if HAVE_ATTRIBUTE_NORETURN -/** - * NORETURN - a function does not return - * - * Used to mark a function which exits; useful for suppressing warnings. - * - * Example: - * static void NORETURN fail(const char *reason) - * { - * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); - * exit(1); - * } - */ -#define NORETURN __attribute__((__noreturn__)) -#else -#define NORETURN -#endif -#endif - -#ifndef PRINTF_FMT -#if HAVE_ATTRIBUTE_PRINTF -/** - * PRINTF_FMT - a function takes printf-style arguments - * @nfmt: the 1-based number of the function's format argument. - * @narg: the 1-based number of the function's first variable argument. - * - * This allows the compiler to check your parameters as it does for printf(). - * - * Example: - * void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...); - */ -#define PRINTF_FMT(nfmt, narg) \ - __attribute__((format(__printf__, nfmt, narg))) -#else -#define PRINTF_FMT(nfmt, narg) -#endif -#endif - -#ifndef CONST_FUNCTION -#if HAVE_ATTRIBUTE_CONST -/** - * CONST_FUNCTION - a function's return depends only on its argument - * - * This allows the compiler to assume that the function will return the exact - * same value for the exact same arguments. This implies that the function - * must not use global variables, or dereference pointer arguments. - */ -#define CONST_FUNCTION __attribute__((__const__)) -#else -#define CONST_FUNCTION -#endif - -#ifndef PURE_FUNCTION -#if HAVE_ATTRIBUTE_PURE -/** - * PURE_FUNCTION - a function is pure - * - * A pure function is one that has no side effects other than it's return value - * and uses no inputs other than it's arguments and global variables. - */ -#define PURE_FUNCTION __attribute__((__pure__)) -#else -#define PURE_FUNCTION -#endif -#endif -#endif - -#if HAVE_ATTRIBUTE_UNUSED -#ifndef UNNEEDED -/** - * UNNEEDED - a variable/function may not be needed - * - * This suppresses warnings about unused variables or functions, but tells - * the compiler that if it is unused it need not emit it into the source code. - * - * Example: - * // With some preprocessor options, this is unnecessary. - * static UNNEEDED int counter; - * - * // With some preprocessor options, this is unnecessary. - * static UNNEEDED void add_to_counter(int add) - * { - * counter += add; - * } - */ -#define UNNEEDED __attribute__((__unused__)) -#endif +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include "config.h" -#ifndef NEEDED -#if HAVE_ATTRIBUTE_USED -/** - * NEEDED - a variable/function is needed - * - * This suppresses warnings about unused variables or functions, but tells - * the compiler that it must exist even if it (seems) unused. - * - * Example: - * // Even if this is unused, these are vital for debugging. - * static NEEDED int counter; - * static NEEDED void dump_counter(void) - * { - * printf("Counter is %i\n", counter); - * } - */ -#define NEEDED __attribute__((__used__)) +#if HAVE_UNALIGNED_ACCESS +#define alignment_ok(p, n) 1 #else -/* Before used, unused functions and vars were always emitted. */ -#define NEEDED __attribute__((__unused__)) -#endif +#define alignment_ok(p, n) ((size_t)(p) % (n) == 0) #endif -#ifndef UNUSED -/** - * UNUSED - a parameter is unused - * - * Some compilers (eg. gcc with -W or -Wunused) warn about unused - * function parameters. This suppresses such warnings and indicates - * to the reader that it's deliberate. - * - * Example: - * // This is used as a callback, so needs to have this prototype. - * static int some_callback(void *unused UNUSED) - * { - * return 0; - * } - */ #define UNUSED __attribute__((__unused__)) -#endif -#else -#ifndef UNNEEDED -#define UNNEEDED -#endif -#ifndef NEEDED -#define NEEDED -#endif -#ifndef UNUSED -#define UNUSED -#endif -#endif - -#ifndef IS_COMPILE_CONSTANT -#if HAVE_BUILTIN_CONSTANT_P -/** - * IS_COMPILE_CONSTANT - does the compiler know the value of this expression? - * @expr: the expression to evaluate - * - * When an expression manipulation is complicated, it is usually better to - * implement it in a function. However, if the expression being manipulated is - * known at compile time, it is better to have the compiler see the entire - * expression so it can simply substitute the result. - * - * This can be done using the IS_COMPILE_CONSTANT() macro. - * - * Example: - * enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON }; - * - * // Out-of-line version. - * const char *greek_name(enum greek greek); - * - * // Inline version. - * static inline const char *_greek_name(enum greek greek) - * { - * switch (greek) { - * case ALPHA: return "alpha"; - * case BETA: return "beta"; - * case GAMMA: return "gamma"; - * case DELTA: return "delta"; - * case EPSILON: return "epsilon"; - * default: return "**INVALID**"; - * } - * } - * - * // Use inline if compiler knows answer. Otherwise call function - * // to avoid copies of the same code everywhere. - * #define greek_name(g) \ - * (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g)) - */ -#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr) -#else -/* If we don't know, assume it's not. */ -#define IS_COMPILE_CONSTANT(expr) 0 -#endif -#endif - -#ifndef WARN_UNUSED_RESULT -#if HAVE_WARN_UNUSED_RESULT -/** - * WARN_UNUSED_RESULT - warn if a function return value is unused. - * - * Used to mark a function where it is extremely unlikely that the caller - * can ignore the result, eg realloc(). - * - * Example: - * // buf param may be freed by this; need return value! - * static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size) - * { - * return realloc(buf, (*size) *= 2); - * } - */ -#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) -#else -#define WARN_UNUSED_RESULT -#endif -#endif - -#if HAVE_ATTRIBUTE_DEPRECATED /** - * WARN_DEPRECATED - warn that a function/type/variable is deprecated when used. + * BUILD_ASSERT - assert a build-time dependency. + * @cond: the compile-time condition which must be true. * - * Used to mark a function, type or variable should not be used. + * Your compile will fail if the condition isn't true, or can't be evaluated + * by the compiler. This can only be used within a function. * * Example: - * WARN_DEPRECATED char *oldfunc(char *buf); + * #include <stddef.h> + * ... + * static char *foo_to_char(struct foo *foo) + * { + * // This code needs string to be at start of foo. + * BUILD_ASSERT(offsetof(struct foo, string) == 0); + * return (char *)foo; + * } */ -#define WARN_DEPRECATED __attribute__((__deprecated__)) -#else -#define WARN_DEPRECATED -#endif - +#define BUILD_ASSERT(cond) \ + do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) -#if HAVE_ATTRIBUTE_NONNULL /** - * NO_NULL_ARGS - specify that no arguments to this function can be NULL. + * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. + * @cond: the compile-time condition which must be true. * - * The compiler will warn if any pointer args are NULL. + * Your compile will fail if the condition isn't true, or can't be evaluated + * by the compiler. This can be used in an expression: its value is "0". * * Example: - * NO_NULL_ARGS char *my_copy(char *buf); + * #define foo_to_char(foo) \ + * ((char *)(foo) \ + * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) */ -#define NO_NULL_ARGS __attribute__((__nonnull__)) +#define BUILD_ASSERT_OR_ZERO(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) -/** - * NON_NULL_ARGS - specify that some arguments to this function can't be NULL. - * @...: 1-based argument numbers for which args can't be NULL. - * - * The compiler will warn if any of the specified pointer args are NULL. - * - * Example: - * char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1); - */ -#define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__))) -#else -#define NO_NULL_ARGS -#define NON_NULL_ARGS(...) -#endif +#define memclear(mem, size) memset(mem, 0, size) +#define memclear_2(m1, s1, m2, s2) { memclear(m1, s1); memclear(m2, s2); } +#define memclear_3(m1, s1, m2, s2, m3, s3) { memclear(m1, s1); memclear(m2, s2); memclear(m3, s3); } -#if HAVE_ATTRIBUTE_RETURNS_NONNULL -/** - * RETURNS_NONNULL - specify that this function cannot return NULL. - * - * Mainly an optimization opportunity, but can also suppress warnings. - * - * Example: - * RETURNS_NONNULL char *my_copy(char *buf); - */ -#define RETURNS_NONNULL __attribute__((__returns_nonnull__)) -#else -#define RETURNS_NONNULL -#endif +static inline void *memcheck_(const void *data, size_t len) +{ + (void)len; + return (void *)data; +} -#if HAVE_ATTRIBUTE_SENTINEL +#if HAVE_TYPEOF /** - * LAST_ARG_NULL - specify the last argument of a variadic function must be NULL. + * memcheck - check that a memory region is initialized + * @data: start of region + * @len: length in bytes * - * The compiler will warn if the last argument isn't NULL. + * When running under valgrind, this causes an error to be printed + * if the entire region is not defined. Otherwise valgrind only + * reports an error when an undefined value is used for a branch, or + * written out. * * Example: - * char *join_string(char *buf, ...) LAST_ARG_NULL; + * // Search for space, but make sure it's all initialized. + * if (memchr(memcheck(somebytes, bytes_len), ' ', bytes_len)) { + * printf("space was found!\n"); + * } */ -#define LAST_ARG_NULL __attribute__((__sentinel__)) +#define memcheck(data, len) ((__typeof__((data)+0))memcheck_((data), (len))) #else -#define LAST_ARG_NULL +#define memcheck(data, len) memcheck_((data), (len)) #endif -#if HAVE_BUILTIN_CPU_SUPPORTS -/** - * cpu_supports - test if current CPU supports the named feature. - * - * This takes a literal string, and currently only works on glibc platforms. - * - * Example: - * if (cpu_supports("mmx")) - * printf("MMX support engaged!\n"); - */ -#define cpu_supports(x) __builtin_cpu_supports(x) -#else -#define cpu_supports(x) 0 -#endif /* HAVE_BUILTIN_CPU_SUPPORTS */ - -#endif /* CCAN_COMPILER_H */ +#endif /* COMPILER_H */ diff --git a/nostrdb/cursor.h b/nostrdb/cursor.h @@ -3,7 +3,6 @@ #define JB55_CURSOR_H #include "typedefs.h" -#include "varint.h" #include <stdio.h> #include <ctype.h> @@ -484,37 +483,11 @@ static inline int parse_str(struct cursor *cur, const char *str) { return 1; } -static inline int is_whitespace(int c) { +static inline int is_whitespace(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; } - -static inline int next_char_is_whitespace(unsigned char *curChar, unsigned char *endChar) { - unsigned char * next = curChar + 1; - if(next > endChar) return 0; - else if(next == endChar) return 1; - return is_whitespace(*next); -} - -static int char_disallowed_at_end_url(char c){ - return c == '.' || c == ','; -} - -static inline int is_final_url_char(unsigned char *curChar, unsigned char *endChar){ - if(is_whitespace(*curChar)){ - return 1; - } - else if(next_char_is_whitespace(curChar, endChar)) { - // next char is whitespace so this char could be the final char in the url - return char_disallowed_at_end_url(*curChar); - } - else{ - // next char isn't whitespace so it can't be a final char - return 0; - } -} - -static inline int is_underscore(int c) { +static inline int is_underscore(char c) { return c == '_'; } @@ -549,7 +522,7 @@ static inline int parse_utf8_char(struct cursor *cursor, unsigned int *code_poin remaining_bytes = 0; *utf8_length = 1; // Assume 1 byte length for unrecognized UTF-8 characters // TODO: We need to gracefully handle unrecognized UTF-8 characters - printf("Invalid UTF-8 byte: %x\n", *code_point); + //printf("Invalid UTF-8 byte: %x\n", *code_point); *code_point = ((first_byte & 0xF0) << 6); // Prevent testing as punctuation return 0; // Invalid first byte } @@ -660,7 +633,7 @@ static inline int consume_until_boundary(struct cursor *cur) { if (!parse_utf8_char(cur, &c, utf8_char_length)) { if (!is_right_boundary(c)){ // TODO: We should work towards handling all UTF-8 characters. - printf("Invalid UTF-8 code point: %x\n", c); + //printf("Invalid UTF-8 code point: %x\n", c); } } } @@ -695,23 +668,6 @@ static inline int consume_until_whitespace(struct cursor *cur, int or_end) { return or_end; } -static inline int consume_until_end_url(struct cursor *cur, int or_end) { - char c; - int consumedAtLeastOne = 0; - - while (cur->p < cur->end) { - c = *cur->p; - - if (is_final_url_char(cur->p, cur->end)) - return consumedAtLeastOne; - - cur->p++; - consumedAtLeastOne = 1; - } - - return or_end; -} - static inline int consume_until_non_alphanumeric(struct cursor *cur, int or_end) { char c; int consumedAtLeastOne = 0; @@ -741,5 +697,13 @@ static inline int cursor_memset(struct cursor *cursor, unsigned char c, int n) return 1; } +static void consume_whitespace_or_punctuation(struct cursor *cur) +{ + while (cur->p < cur->end) { + if (!is_right_boundary(*cur->p)) + return; + cur->p++; + } +} #endif