Initial commit
This commit is contained in:
commit
087645848b
|
@ -0,0 +1,9 @@
|
|||
# Build files
|
||||
/build
|
||||
|
||||
# Qt Creator files
|
||||
/CMakeLists.txt.user*
|
||||
/liberty.config
|
||||
/liberty.files
|
||||
/liberty.creator*
|
||||
/liberty.includes
|
|
@ -0,0 +1,18 @@
|
|||
language: c
|
||||
notifications:
|
||||
irc:
|
||||
channels: "anathema.us.nu#anathema"
|
||||
use_notice: true
|
||||
skip_join: true
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
before_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
script:
|
||||
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- make
|
||||
- ctest -V
|
|
@ -0,0 +1,34 @@
|
|||
project (liberty C)
|
||||
cmake_minimum_required (VERSION 2.8.5)
|
||||
|
||||
# Moar warnings
|
||||
if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
|
||||
# -Wunused-function is pretty annoying here, as everything is static
|
||||
set (CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -Wno-unused-function")
|
||||
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
|
||||
|
||||
# Dependencies
|
||||
find_package (PkgConfig REQUIRED)
|
||||
pkg_check_modules (libssl REQUIRED libssl libcrypto)
|
||||
|
||||
# -lpthread is only there for debugging (gdb & errno)
|
||||
# -lrt is only for glibc < 2.17
|
||||
set (common_libraries ${libssl_LIBRARIES} rt pthread)
|
||||
include_directories (${libssl_INCLUDE_DIRS})
|
||||
link_directories (${libssl_LIBRARY_DIRS})
|
||||
|
||||
# Generate a configuration file
|
||||
# TODO: actualy use the configuration file for something; so far we allow
|
||||
# for direct inclusion without running this CMakeLists.txt
|
||||
configure_file (${PROJECT_SOURCE_DIR}/liberty-config.h.in
|
||||
${PROJECT_BINARY_DIR}/liberty-config.h)
|
||||
include_directories (${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR})
|
||||
set (common_sources ${PROJECT_BINARY_DIR}/liberty-config.h)
|
||||
|
||||
# Build some unit tests
|
||||
enable_testing ()
|
||||
foreach (name liberty)
|
||||
add_executable (test-${name} tests/${name}.c ${common_sources})
|
||||
target_link_libraries (test-${name} ${common_libraries})
|
||||
add_test (test-${name} test-${name})
|
||||
endforeach (name)
|
|
@ -0,0 +1,14 @@
|
|||
Copyright (c) 2014 - 2015, Přemysl Janouch <p.janouch@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,20 @@
|
|||
liberty
|
||||
=======
|
||||
|
||||
`liberty' is a pseudolibrary of all the common C code I have written for various
|
||||
projects. It can be thought of as a successor to my other C library, libxtnd.
|
||||
|
||||
You are supposed to import it as a git submodule and include the main source
|
||||
file directly everywhere you need it. Everything is declared "static". I have
|
||||
come to the conclusion that this style of C programming suits me the best, as it
|
||||
allows me to nearly forget about the mess that are header files.
|
||||
|
||||
License
|
||||
-------
|
||||
`liberty' is written by Přemysl Janouch <p.janouch@gmail.com>.
|
||||
|
||||
You may use the software under the terms of the ISC license, the text of which
|
||||
is included within the package, or, at your option, you may relicense the work
|
||||
under the MIT or the Modified BSD License, as listed at the following site:
|
||||
|
||||
http://www.gnu.org/licenses/license-list.html
|
|
@ -0,0 +1,87 @@
|
|||
// Code taken from https://github.com/floodyberry/siphash with some edits.
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related and neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
|
||||
#include "siphash.h"
|
||||
|
||||
inline static uint64_t
|
||||
u8to64_le (const unsigned char *p)
|
||||
{
|
||||
return
|
||||
(uint64_t) p[0] |
|
||||
(uint64_t) p[1] << 8 |
|
||||
(uint64_t) p[2] << 16 |
|
||||
(uint64_t) p[3] << 24 |
|
||||
(uint64_t) p[4] << 32 |
|
||||
(uint64_t) p[5] << 40 |
|
||||
(uint64_t) p[6] << 48 |
|
||||
(uint64_t) p[7] << 56 ;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
siphash (const unsigned char key[16], const unsigned char *m, size_t len)
|
||||
{
|
||||
uint64_t v0, v1, v2, v3;
|
||||
uint64_t mi, k0, k1;
|
||||
uint64_t last7;
|
||||
size_t i, blocks;
|
||||
|
||||
k0 = u8to64_le (key + 0);
|
||||
k1 = u8to64_le (key + 8);
|
||||
v0 = k0 ^ 0x736f6d6570736575ull;
|
||||
v1 = k1 ^ 0x646f72616e646f6dull;
|
||||
v2 = k0 ^ 0x6c7967656e657261ull;
|
||||
v3 = k1 ^ 0x7465646279746573ull;
|
||||
|
||||
last7 = (uint64_t) (len & 0xff) << 56;
|
||||
|
||||
#define ROTL64(a,b) (((a)<<(b))|((a)>>(64-b)))
|
||||
|
||||
#define COMPRESS \
|
||||
v0 += v1; v2 += v3; \
|
||||
v1 = ROTL64 (v1,13); v3 = ROTL64 (v3,16); \
|
||||
v1 ^= v0; v3 ^= v2; \
|
||||
v0 = ROTL64 (v0,32); \
|
||||
v2 += v1; v0 += v3; \
|
||||
v1 = ROTL64 (v1,17); v3 = ROTL64 (v3,21); \
|
||||
v1 ^= v2; v3 ^= v0; \
|
||||
v2 = ROTL64(v2,32);
|
||||
|
||||
for (i = 0, blocks = (len & ~(size_t) 7); i < blocks; i += 8)
|
||||
{
|
||||
mi = u8to64_le (m + i);
|
||||
v3 ^= mi;
|
||||
COMPRESS
|
||||
COMPRESS
|
||||
v0 ^= mi;
|
||||
}
|
||||
|
||||
switch (len - blocks)
|
||||
{
|
||||
case 7: last7 |= (uint64_t) m[i + 6] << 48;
|
||||
case 6: last7 |= (uint64_t) m[i + 5] << 40;
|
||||
case 5: last7 |= (uint64_t) m[i + 4] << 32;
|
||||
case 4: last7 |= (uint64_t) m[i + 3] << 24;
|
||||
case 3: last7 |= (uint64_t) m[i + 2] << 16;
|
||||
case 2: last7 |= (uint64_t) m[i + 1] << 8;
|
||||
case 1: last7 |= (uint64_t) m[i + 0] ;
|
||||
default:;
|
||||
};
|
||||
v3 ^= last7;
|
||||
COMPRESS
|
||||
COMPRESS
|
||||
v0 ^= last7;
|
||||
v2 ^= 0xff;
|
||||
COMPRESS
|
||||
COMPRESS
|
||||
COMPRESS
|
||||
COMPRESS
|
||||
|
||||
return v0 ^ v1 ^ v2 ^ v3;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef SIPHASH_H
|
||||
#define SIPHASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
uint64_t siphash (const unsigned char key[16],
|
||||
const unsigned char *m, size_t len);
|
||||
|
||||
#endif // SIPHASH_H
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* tests/liberty.c
|
||||
*
|
||||
* Copyright (c) 2015, Přemysl Janouch <p.janouch@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define PROGRAM_NAME "test"
|
||||
#define PROGRAM_VERSION "0"
|
||||
|
||||
#include "../liberty.c"
|
||||
|
||||
// --- Memory ------------------------------------------------------------------
|
||||
|
||||
#define KILO 1024
|
||||
#define MEGA 1048576
|
||||
|
||||
static void
|
||||
test_memory (void)
|
||||
{
|
||||
void *m = xmalloc (MEGA);
|
||||
memset (m, 0, MEGA);
|
||||
|
||||
void *n = xcalloc (KILO, KILO);
|
||||
soft_assert (!memcmp (n, m, MEGA));
|
||||
|
||||
m = xrealloc (m, 1024);
|
||||
n = xreallocarray (n, KILO, 1);
|
||||
soft_assert (!memcmp (n, m, KILO));
|
||||
|
||||
free (m);
|
||||
free (n);
|
||||
|
||||
char *s = xstrdup ("test");
|
||||
char *t = xstrndup ("testing", 4);
|
||||
soft_assert (!strcmp (s, t));
|
||||
|
||||
free (s);
|
||||
free (t);
|
||||
}
|
||||
|
||||
// --- Linked lists ------------------------------------------------------------
|
||||
|
||||
struct my_link
|
||||
{
|
||||
LIST_HEADER (struct my_link)
|
||||
int n;
|
||||
};
|
||||
|
||||
static struct my_link *
|
||||
make_link (int value)
|
||||
{
|
||||
struct my_link *link = xcalloc (1, sizeof *link);
|
||||
link->n = value;
|
||||
return link;
|
||||
}
|
||||
|
||||
static void
|
||||
check_linked_list (struct my_link *list, struct my_link **a, int n)
|
||||
{
|
||||
// The linked list must contain items from the array, in that order
|
||||
struct my_link *iter = list;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (!a[i])
|
||||
continue;
|
||||
|
||||
hard_assert (iter != NULL);
|
||||
soft_assert (iter->n == i);
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
// And nothing more
|
||||
soft_assert (iter == NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_list (void)
|
||||
{
|
||||
struct my_link *list = NULL;
|
||||
struct my_link *a[10];
|
||||
|
||||
// Prepare a linked list
|
||||
for (int i = N_ELEMENTS (a); i--; )
|
||||
{
|
||||
a[i] = make_link (i);
|
||||
LIST_PREPEND (list, a[i]);
|
||||
}
|
||||
|
||||
// Remove a few entries
|
||||
LIST_UNLINK (list, a[0]); a[0] = NULL;
|
||||
LIST_UNLINK (list, a[3]); a[3] = NULL;
|
||||
LIST_UNLINK (list, a[4]); a[4] = NULL;
|
||||
LIST_UNLINK (list, a[6]); a[6] = NULL;
|
||||
|
||||
// Prepend one more item
|
||||
a[0] = make_link (0);
|
||||
LIST_PREPEND (list, a[0]);
|
||||
|
||||
// Check the contents
|
||||
check_linked_list (list, a, N_ELEMENTS (a));
|
||||
|
||||
// Destroy the linked list
|
||||
LIST_FOR_EACH (struct my_link, iter, list)
|
||||
free (iter);
|
||||
}
|
||||
|
||||
static void
|
||||
test_list_with_tail (void)
|
||||
{
|
||||
struct my_link *list = NULL;
|
||||
struct my_link *tail = NULL;
|
||||
struct my_link *a[10];
|
||||
|
||||
// Prepare a linked list
|
||||
for (int i = 0; i < (int) N_ELEMENTS (a); i++)
|
||||
{
|
||||
a[i] = make_link (i);
|
||||
LIST_APPEND_WITH_TAIL (list, tail, a[i]);
|
||||
}
|
||||
|
||||
// Remove a few entries
|
||||
LIST_UNLINK_WITH_TAIL (list, tail, a[0]); a[0] = NULL;
|
||||
LIST_UNLINK_WITH_TAIL (list, tail, a[3]); a[3] = NULL;
|
||||
LIST_UNLINK_WITH_TAIL (list, tail, a[4]); a[4] = NULL;
|
||||
LIST_UNLINK_WITH_TAIL (list, tail, a[6]); a[6] = NULL;
|
||||
LIST_UNLINK_WITH_TAIL (list, tail, a[9]); a[9] = NULL;
|
||||
|
||||
// Append one more item
|
||||
a[9] = make_link (9);
|
||||
LIST_APPEND_WITH_TAIL (list, tail, a[9]);
|
||||
|
||||
// Check the contents
|
||||
check_linked_list (list, a, N_ELEMENTS (a));
|
||||
|
||||
// Destroy the linked list
|
||||
LIST_FOR_EACH (struct my_link, iter, list)
|
||||
free (iter);
|
||||
}
|
||||
|
||||
// --- Strings -----------------------------------------------------------------
|
||||
|
||||
static void
|
||||
test_str_vector (void)
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
|
||||
str_vector_add_owned (&v, xstrdup ("xkcd"));
|
||||
str_vector_reset (&v);
|
||||
|
||||
const char *a[] =
|
||||
{ "123", "456", "a", "bc", "def", "ghij", "klmno", "pqrstu" };
|
||||
|
||||
// Add the first two items via another vector
|
||||
struct str_vector w;
|
||||
str_vector_init (&w);
|
||||
str_vector_add_args (&w, a[0], a[1], NULL);
|
||||
str_vector_add_vector (&v, w.vector);
|
||||
str_vector_free (&w);
|
||||
|
||||
// Add an item and delete it right after
|
||||
str_vector_add (&v, "test");
|
||||
str_vector_remove (&v, v.len - 1);
|
||||
|
||||
// Add the rest of the list properly
|
||||
for (int i = 2; i < (int) N_ELEMENTS (a); i++)
|
||||
str_vector_add (&v, a[i]);
|
||||
|
||||
// Check the contents
|
||||
soft_assert (v.len == N_ELEMENTS (a));
|
||||
for (int i = 0; i < (int) N_ELEMENTS (a); i++)
|
||||
soft_assert (!strcmp (v.vector[i], a[i]));
|
||||
soft_assert (v.vector[v.len] == NULL);
|
||||
|
||||
str_vector_free (&v);
|
||||
}
|
||||
|
||||
static void
|
||||
test_str (void)
|
||||
{
|
||||
uint8_t x[] = { 0x12, 0x34, 0x56, 0x78, 0x11, 0x22, 0x33, 0x44 };
|
||||
|
||||
struct str s;
|
||||
str_init (&s);
|
||||
str_ensure_space (&s, MEGA);
|
||||
str_append_data (&s, x, sizeof x);
|
||||
str_remove_slice (&s, 4, 4);
|
||||
soft_assert (s.len == 4);
|
||||
|
||||
struct str t;
|
||||
str_init (&t);
|
||||
str_append_str (&t, &s);
|
||||
str_append (&t, "abc");
|
||||
str_append_c (&t, 'd');
|
||||
str_append_printf (&t, "efg");
|
||||
|
||||
char *y = str_steal (&t);
|
||||
soft_assert (!strcmp (y, "\x12\x34\x56\x78" "abcdefg"));
|
||||
free (y);
|
||||
|
||||
str_reset (&s);
|
||||
str_free (&s);
|
||||
}
|
||||
|
||||
// --- Errors ------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
test_error (void)
|
||||
{
|
||||
const char *m = "something fucked up";
|
||||
|
||||
struct error *e = NULL;
|
||||
error_set (&e, "%s", m);
|
||||
|
||||
struct error *f = NULL;
|
||||
error_propagate (&f, e);
|
||||
|
||||
soft_assert (f != NULL);
|
||||
soft_assert (!strcmp (f->message, m));
|
||||
error_free (f);
|
||||
}
|
||||
|
||||
// --- Hash map ----------------------------------------------------------------
|
||||
|
||||
static int
|
||||
tolower_ascii (int c)
|
||||
{
|
||||
return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
static size_t
|
||||
tolower_strxfrm (char *dest, const char *src, size_t n)
|
||||
{
|
||||
size_t len = strlen (src);
|
||||
while (n-- && (*dest++ = tolower_ascii (*src++)))
|
||||
;
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
free_counter (void *data)
|
||||
{
|
||||
int *counter = data;
|
||||
if (!--*counter)
|
||||
free (data);
|
||||
}
|
||||
|
||||
static int *
|
||||
make_counter (void)
|
||||
{
|
||||
int *counter = xmalloc (sizeof *counter);
|
||||
*counter = 1;
|
||||
return counter;
|
||||
}
|
||||
|
||||
static int *
|
||||
ref_counter (int *counter)
|
||||
{
|
||||
(*counter)++;
|
||||
return counter;
|
||||
}
|
||||
|
||||
static void
|
||||
test_str_map (void)
|
||||
{
|
||||
// Put two reference counted objects in the map under case-insensitive keys
|
||||
struct str_map m;
|
||||
str_map_init (&m);
|
||||
m.key_xfrm = tolower_strxfrm;
|
||||
m.free = free_counter;
|
||||
|
||||
int *a = make_counter ();
|
||||
int *b = make_counter ();
|
||||
|
||||
str_map_set (&m, "abc", ref_counter (a));
|
||||
soft_assert (str_map_find (&m, "ABC") == a);
|
||||
soft_assert (!str_map_find (&m, "DEFghi"));
|
||||
|
||||
str_map_set (&m, "defghi", ref_counter (b));
|
||||
soft_assert (str_map_find (&m, "ABC") == a);
|
||||
soft_assert (str_map_find (&m, "DEFghi") == b);
|
||||
|
||||
// Check that we can iterate over both of them
|
||||
struct str_map_iter iter;
|
||||
str_map_iter_init (&iter, &m);
|
||||
|
||||
bool met_a = false;
|
||||
bool met_b = false;
|
||||
void *iter_data;
|
||||
while ((iter_data = str_map_iter_next (&iter)))
|
||||
{
|
||||
if (iter_data == a) { soft_assert (!met_a); met_a = true; }
|
||||
if (iter_data == b) { soft_assert (!met_b); met_b = true; }
|
||||
soft_assert (met_a || met_b);
|
||||
}
|
||||
soft_assert (met_a && met_b);
|
||||
|
||||
// Remove one of the keys
|
||||
str_map_set (&m, "abc", NULL);
|
||||
soft_assert (!str_map_find (&m, "ABC"));
|
||||
soft_assert (str_map_find (&m, "DEFghi") == b);
|
||||
|
||||
str_map_free (&m);
|
||||
|
||||
// Check that the objects have been destroyed exactly once
|
||||
soft_assert (*a == 1);
|
||||
soft_assert (*b == 1);
|
||||
free_counter (a);
|
||||
free_counter (b);
|
||||
}
|
||||
|
||||
// --- Main --------------------------------------------------------------------
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
struct test test;
|
||||
test_init (&test, argc, argv);
|
||||
|
||||
test_add_simple (&test, "/memory", NULL, test_memory);
|
||||
test_add_simple (&test, "/list", NULL, test_list);
|
||||
test_add_simple (&test, "/list-with-tail", NULL, test_list_with_tail);
|
||||
test_add_simple (&test, "/str-vector", NULL, test_str_vector);
|
||||
test_add_simple (&test, "/str", NULL, test_str);
|
||||
test_add_simple (&test, "/error", NULL, test_error);
|
||||
test_add_simple (&test, "/str-map", NULL, test_str_map);
|
||||
|
||||
// TODO: write tests for the rest of the library
|
||||
|
||||
return test_run (&test);
|
||||
}
|
Loading…
Reference in New Issue