From: Rusty Russell Date: Tue, 26 Jun 2012 06:46:18 +0000 (+0930) Subject: bytestring: new module. X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=8253b9dd5d279793e267ed5dfcc4c0f2cfbaeb83 bytestring: new module. --- diff --git a/ccan/bytestring/LICENSE b/ccan/bytestring/LICENSE new file mode 120000 index 00000000..dc314eca --- /dev/null +++ b/ccan/bytestring/LICENSE @@ -0,0 +1 @@ +../../licenses/LGPL-2.1 \ No newline at end of file diff --git a/ccan/bytestring/_info b/ccan/bytestring/_info new file mode 100644 index 00000000..5b084916 --- /dev/null +++ b/ccan/bytestring/_info @@ -0,0 +1,41 @@ +#include +#include "config.h" + +/** + * bytestring - simple bytestring handling + * + * This code handles manipulation of "bytestrings" represented as a + * structure containing a pointer and length. Bytestrings are not + * NUL-terminated, and may include internal \0 characters. The main + * use case is for referencing sub-sections of a large data buffer + * without the inconvenience of manually passing (and returning) both + * pointer and length all the time. + * + * Because of this use case, the bytestrings are treated as having + * immutable contents (we use a const char pointer). The caller code + * is responsible for ensuring that the lifetime of the data + * referenced by the bytestrings is long enough not to leave + * bytestring structures with a dangling pointer. + * + * Example: + * const char buf[] = "ABCDEFGH"; + * struct bytestring abcd = BYTESTRING("ABCD"); + * + * assert(bytestring_eq(bytestring(buf, 4), abcd)); + * + * License: LGPL (v2.1 or any later version) + * Author: David Gibson + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/array_size\n"); + return 0; + } + + return 1; +} diff --git a/ccan/bytestring/bytestring.h b/ccan/bytestring/bytestring.h new file mode 100644 index 00000000..ee4087d4 --- /dev/null +++ b/ccan/bytestring/bytestring.h @@ -0,0 +1,81 @@ +/* Licensed under LGPLv2+ - see LICENSE file for details */ +#ifndef CCAN_BYTESTRING_H_ +#define CCAN_BYTESTRING_H_ + +#include +#include +#include + +#include + +struct bytestring { + const char *ptr; + size_t len; +}; + +/** + * bytestring - construct a new bytestring + * @p: pointer to the content of the bytestring + * @l: length of the bytestring + * + * Builds a new bytestring starting at p, of length l. + * + * Example: + * char x[5] = "abcde"; + * struct bytestring bs = bytestring(x, 5); + * assert(bs.len == 5); + */ +static inline struct bytestring bytestring(const char *p, size_t l) +{ + struct bytestring bs = { + .ptr = p, + .len = l, + }; + + return bs; +} + +#define bytestring_NULL bytestring(NULL, 0) + +/** + * BYTESTRING - construct a bytestring from a string literal + * @s: string literal + * + * Builds a new bytestring containing the given literal string, not + * including the terminating \0 (but including any internal \0s). + * + * Example: + * assert(BYTESTRING("abc\0def").len == 7); + */ +#define BYTESTRING(s) (bytestring((s), ARRAY_SIZE(s) - 1)) + + +/** + * bytestring_from_string - construct a bytestring from a NUL terminated string + * @s: NUL-terminated string pointer + * + * Builds a new bytestring containing the given NUL-terminated string, + * up to, but not including, the terminating \0. + * + * Example: + * assert(bytestring_from_string("abc\0def").len == 3); + */ +static inline struct bytestring bytestring_from_string(const char *s) +{ + return bytestring(s, strlen(s)); +} + +/** + * bytestring_eq - test if bytestrings have identical content + * @a, @b: bytestrings + * + * Returns 1 if the given bytestrings have identical length and + * content, 0 otherwise. + */ +static inline bool bytestring_eq(struct bytestring a, struct bytestring b) +{ + return (a.len == b.len) + && (memcmp(a.ptr, b.ptr, a.len) == 0); +} + +#endif /* CCAN_BYTESTRING_H_ */ diff --git a/ccan/bytestring/test/compile_fail-BYTESTRING-2.c b/ccan/bytestring/test/compile_fail-BYTESTRING-2.c new file mode 100644 index 00000000..7ab06f82 --- /dev/null +++ b/ccan/bytestring/test/compile_fail-BYTESTRING-2.c @@ -0,0 +1,15 @@ +#include + +#include + +int main(int argc, char *argv[]) +{ + struct bytestring bs; + const char *x = "abcde"; + +#ifdef FAIL + bs = BYTESTRING(x); +#endif + printf("%zd %s\n", bs.len, x); + return 0; +} diff --git a/ccan/bytestring/test/compile_fail-BYTESTRING.c b/ccan/bytestring/test/compile_fail-BYTESTRING.c new file mode 100644 index 00000000..f3fcb20d --- /dev/null +++ b/ccan/bytestring/test/compile_fail-BYTESTRING.c @@ -0,0 +1,18 @@ +#include + +#include + +int main(int argc, char *argv[]) +{ + struct bytestring bs; + + bs = BYTESTRING( +#ifdef FAIL + argv[0] +#else + "literal" +#endif +); + printf("%zd\n", bs.len); + return 0; +} diff --git a/ccan/bytestring/test/run.c b/ccan/bytestring/test/run.c new file mode 100644 index 00000000..49c16a6a --- /dev/null +++ b/ccan/bytestring/test/run.c @@ -0,0 +1,35 @@ +#include +#include + +#define TEST_STRING "test string" +#define TEST_STRING_2 "abc\0def" + +const char str1[] = TEST_STRING; +const char *str2 = TEST_STRING; + +int main(void) +{ + struct bytestring bs, bs1, bs2, bs3, bs4; + + /* This is how many tests you plan to run */ + plan_tests(6); + + bs = bytestring(str1, sizeof(str1) - 1); + ok1(bs.ptr == str1); + ok1(bs.len == (sizeof(str1) - 1)); + + bs1 = BYTESTRING(TEST_STRING); + ok1(bytestring_eq(bs, bs1)); + + bs2 = BYTESTRING(TEST_STRING_2); + ok1(bs2.len == 7); + + bs3 = bytestring_from_string(str2); + ok1(bytestring_eq(bs3, bs)); + + bs4 = bytestring_from_string(TEST_STRING_2); + ok1(bs4.len == 3); + + /* This exits depending on whether all tests passed */ + return exit_status(); +}