nostrdb: add supporting files before the move commit

This commit is contained in:
William Casarin
2024-01-25 14:23:36 -08:00
committed by Daniel D’Aquino
parent 4a6121ba13
commit 389c2c9695
4 changed files with 441 additions and 350 deletions

217
nostrdb/bech32.c Normal file
View File

@@ -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;
}

142
nostrdb/bech32.h Normal file
View File

@@ -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 */

View File

@@ -1,317 +1,85 @@
/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_COMPILER_H
#define CCAN_COMPILER_H
#ifndef COMPILER_H
#define COMPILER_H
#include <stdbool.h>
#include <stdlib.h>
#include <string.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__))
#if HAVE_UNALIGNED_ACCESS
#define alignment_ok(p, n) 1
#else
#define COLD
#endif
#define alignment_ok(p, n) ((size_t)(p) % (n) == 0)
#endif
#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
#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__))
#else
/* Before used, unused functions and vars were always emitted. */
#define NEEDED __attribute__((__unused__))
#endif
#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.
*
* Used to mark a function, type or variable should not be used.
*
* Example:
* WARN_DEPRECATED char *oldfunc(char *buf);
*/
#define WARN_DEPRECATED __attribute__((__deprecated__))
#else
#define WARN_DEPRECATED
#endif
#if HAVE_ATTRIBUTE_NONNULL
/**
* NO_NULL_ARGS - specify that no arguments to this function can be NULL.
*
* The compiler will warn if any pointer args are NULL.
*
* Example:
* NO_NULL_ARGS char *my_copy(char *buf);
*/
#define NO_NULL_ARGS __attribute__((__nonnull__))
/**
* 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.
* BUILD_ASSERT - assert a build-time dependency.
* @cond: the compile-time condition which must be true.
*
* The compiler will warn if any of the specified pointer args are NULL.
* 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:
* char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1);
* #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 NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__)))
#define BUILD_ASSERT(cond) \
do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
/**
* BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
* @cond: the compile-time condition which must be true.
*
* 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:
* #define foo_to_char(foo) \
* ((char *)(foo) \
* + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
*/
#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)
#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); }
static inline void *memcheck_(const void *data, size_t len)
{
(void)len;
return (void *)data;
}
#if HAVE_TYPEOF
/**
* memcheck - check that a memory region is initialized
* @data: start of region
* @len: length in bytes
*
* 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:
* // Search for space, but make sure it's all initialized.
* if (memchr(memcheck(somebytes, bytes_len), ' ', bytes_len)) {
* printf("space was found!\n");
* }
*/
#define memcheck(data, len) ((__typeof__((data)+0))memcheck_((data), (len)))
#else
#define NO_NULL_ARGS
#define NON_NULL_ARGS(...)
#define memcheck(data, len) memcheck_((data), (len))
#endif
#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
#if HAVE_ATTRIBUTE_SENTINEL
/**
* LAST_ARG_NULL - specify the last argument of a variadic function must be NULL.
*
* The compiler will warn if the last argument isn't NULL.
*
* Example:
* char *join_string(char *buf, ...) LAST_ARG_NULL;
*/
#define LAST_ARG_NULL __attribute__((__sentinel__))
#else
#define LAST_ARG_NULL
#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 */

View File

@@ -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