Initial commit

This commit is contained in:
Přemysl Eric Janouch 2015-02-28 19:53:23 +01:00
commit 087645848b
10 changed files with 3114 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
# Build files
/build
# Qt Creator files
/CMakeLists.txt.user*
/liberty.config
/liberty.files
/liberty.creator*
/liberty.includes

18
.travis.yml Normal file
View File

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

34
CMakeLists.txt Normal file
View File

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

14
LICENSE Normal file
View File

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

20
README Normal file
View File

@ -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
liberty-config.h.in Normal file
View File

2577
liberty.c Normal file

File diff suppressed because it is too large Load Diff

87
siphash.c Normal file
View File

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

10
siphash.h Normal file
View File

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

345
tests/liberty.c Normal file
View File

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