Initial import of libucore

This commit is contained in:
Nils O. Selåsdal
2012-10-29 23:07:32 +01:00
commit ed3866e49a
79 changed files with 6181 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
import os
import platform
#version info of the library
revision = svn_version = os.popen('svnversion').read()[:-1]
version_info = {
'version_major': 1 ,
'version_minor': 0 ,
'version_patch': 0 ,
'version_revision': revision,
}
AddOption('--build_type',
dest = 'build_type',
type = 'string',
nargs = 1,
action='store',
default='debug',
metavar='TYPE',
help = 'debug|release - Build a Debug (default) or Release variant'
)
AddOption('--prefix',
dest='prefix',
type='string',
nargs=1,
action='store',
metavar='DIR',
default='/usr',
help='installation prefix'
)
AddOption('--test_xml',
dest='test_xml',
action='store_true',
help='Create a result.xml when running the testsuite'
)
build_type = GetOption('build_type')
test_xml = GetOption('test_xml')
prefix = GetOption('prefix')
if not (build_type in ['debug', 'release']):
print "Error: expected 'debug' or 'release', found: " + build_type
Exit(1)
def InstallPerm(env, dest, files, perm):
obj = env.Install(dest, files)
for i in obj:
env.AddPostAction(i, Chmod(str(i), perm))
return dest
env = Environment(tools = ['default', 'textfile'])
env.AddMethod(InstallPerm)
Export('env', 'build_type', 'prefix', 'version_info', 'test_xml')
env['CFLAGS'] = ['-Wall', '-Wextra', '-pipe', '-ggdb']
env['LINKFLAGS'] = ['-O2']
env['CPPDEFINES'] = ['_FILE_OFFSET_BITS=64']
if build_type == 'release':
env['CFLAGS'] += ['-O2']
#this will turn off assert()
env['CPPDEFINES'] += ['NDEBUG']
elif build_type == 'debug':
env['CPPDEFINES'] += ['DEBUG']
#put all .sconsign files in one place
env.SConsignFile()
subdirs = [
'src',
'test'
]
for subdir in subdirs:
SConscript(subdir + '/SConscript', variant_dir='#build/' + subdir, src_dir='#'+subdir, duplicate=0)
env.Default('src')
+26
View File
@@ -0,0 +1,26 @@
import os
Import('env', 'build_type', 'prefix', 'version_info')
ucore_env = env.Clone()
#substitute @version_xx@ strings
subst_version_info = dict(('@' + key + '@', version_info[key]) for key in version_info)
ucore_env.Substfile('ucore_version.c.in', SUBST_DICT = subst_version_info)
sources = ucore_env.Glob('*.c')
headers = ucore_env.Glob('*.h')
#print 'ucore_env', dir(ucore_env)
#print ucore_env.Dump()
#print 'sources:', sources[len(sources)-2]
#Build library
ucore_lib = ucore_env.StaticLibrary(target='ucore_' + build_type , source=sources)
#install targets
ucore_env.Alias('install',
ucore_env.Install(os.path.join(prefix, 'lib'), ucore_lib))
ucore_env.Alias('install',
ucore_env.InstallPerm(os.path.join(prefix, 'include', 'ucore'), headers, 0644))
+97
View File
@@ -0,0 +1,97 @@
#ifndef IO_MUX_H_
#define IO_MUX_H_
#include "ucore_timers.h"
#define MUX_EV_READ (1 << 0x00)
#define MUX_EV_WRITE (1 << 0x01)
//#define MUX_EV_EXCEPT (1 << 0x02)
#define MUX_EV_MASK (MUX_EV_READ | MUX_EV_WRITE )
/**
* mux implementation to use
*/
enum IOMUX_TYPE {
IOMUX_TYPE_DEFAULT = 0,
IOMUX_TYPE_SELECT,
IOMUX_TYPE_EPOLL
};
/** Opaque struct */
struct IOMux;
struct IOMuxFD;
typedef void (*iomux_cb)(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event);
/** Represents a watched file descriptor */
struct IOMuxFD {
/** The file descriptor */
int fd;
/** The events to watch for, MUX_EV_XX mask */
unsigned int what;
/** callback to call on an event */
iomux_cb callback;
/** values available to the caller. These will bbe passed
* back on the callback */
void *cookie_ptr;
int cookie_int;
int cookie_int2;
};
/** Creates a new IOMux.
*/
struct IOMux *iomux_create(enum IOMUX_TYPE type);
/** Deletes the IOMux and frees its resources.
* Can not be called from within a callback */
void iomux_delete(struct IOMux *mux);
/** Runs the event loop of the mux
* returns if the number of file descriptors is 0 or
* an error occurs */
int iomux_run(struct IOMux *mux);
/* Adds a file descriptor to the watch set,
* returns 0 on success, an errno value on error */
int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd);
/** Removes the file descriptor*/
int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd);
/** Updates the events to watch for in fd->what
* returns 0 on success, an errno value on error */
int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd);
/**
* Convenience macro for setting the new event
*/
#define iomux_set_event(mux, fd, what)\
({\
(fd)->what = (what);\
iomux_update_events((mux), (fd));\
})
/**
* Convenience macro for clearing the new event
*/
#define iomux_clear_event(mux, fd, what)\
({\
(fd)->what &= ~(what);\
iomux_update_events((mux), (fd));\
})
/**
* Convenience macro for adding the new event to the existing events
*/
#define iomux_add_event(mux, fd, what)\
({\
(fd)->what &= (what);\
iomux_update_events((mux), (fd));\
})
/** Returns a UCTimer instance tied to this mux.
* Used to schedule timers within this mux.
*/
struct UCTimers *iomux_get_timers(struct IOMux *mux);
#endif
+224
View File
@@ -0,0 +1,224 @@
#include <sys/epoll.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include "iomux_impl.h"
//epoll (linux specific) IO mux.
//We stuff the struct IOMuxFD pointer in the event.data.ptr slot
//for the kernel to keep track of, so we don't have to.
///we do not use edge triggered mode
//number of events we wait for in one go
#define EPOLL_WAIT_EVENTS (256)
struct IOMuxEpoll {
//number of file descriptors we're watching
size_t num_descriptors;
//the epoll file descriptor
int epoll_fd;
struct epoll_event pending_events[EPOLL_WAIT_EVENTS];
//number of pending events
int pending;
};
static inline uint32_t mux_2_epoll_events(unsigned int events)
{
uint32_t epoll_events = 0;
if(events & MUX_EV_READ)
epoll_events |= EPOLLIN;
if(events & MUX_EV_WRITE)
epoll_events |= EPOLLOUT;
return epoll_events;
}
static inline unsigned int epoll_2_mux_events(uint32_t events)
{
unsigned int mux_events = 0;
//epoll always waits for EPOLLHUP and EPOLLERR , we map
//those to read events which will hopefully do the right thing
if(events & (EPOLLIN | EPOLLHUP | EPOLLERR))
mux_events |= MUX_EV_READ;
if(events & EPOLLOUT)
mux_events |= MUX_EV_WRITE;
return mux_events;
}
static int iomux_epoll_update_events(struct IOMux *mux_, struct IOMuxFD *fd)
{
struct IOMuxEpoll *mux = mux_->instance;
struct epoll_event e_event = {0, {0}};
int rc;
//if we EPOLL_CTL_MOD with events of 0, epoll
//will still wait for HUP/ERR , which can lead to
//strange things. (e.g. updating fd->what to 0 on a pipe
//in order to try to "pause" reading can lead to missing or false
//read events.
assert(fd->what != 0);
if(fd->what == 0)
return EINVAL;
e_event.events = mux_2_epoll_events(fd->what);
e_event.data.ptr = fd;
rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_MOD, fd->fd, &e_event);
assert(rc == 0);
if(rc != 0)
return errno;
return 0;
}
static int iomux_epoll_register_fd(struct IOMux *mux_, struct IOMuxFD *fd)
{
struct IOMuxEpoll *mux = mux_->instance;
struct epoll_event e_event = {0, {0}};
int rc;
if(fd->what == 0 || fd->callback == NULL)
return EINVAL;
e_event.events = mux_2_epoll_events(fd->what);
e_event.data.ptr = fd;
rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_ADD, fd->fd, &e_event);
assert(rc == 0);
if(rc != 0) {
return errno;
}
mux->num_descriptors++;
return 0;
}
static int iomux_epoll_unregister_fd(struct IOMux *mux_, struct IOMuxFD *fd)
{
struct IOMuxEpoll *mux = mux_->instance;
struct epoll_event e_event = {0,{ 0}};
int i;
int rc;
rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_DEL, fd->fd, &e_event);
assert(rc == 0);
if(rc != 0)
return errno;
//if the fd is pending, remove it from pending_events
//This ensures that it's safe to unregister a descriptor
//that is currently pending a callback
for(i = 0; i < mux->pending; i++) {
struct IOMuxFD *fdi = mux->pending_events[i].data.ptr;
if(fdi == NULL)
continue;
if(fd == fdi) {
mux->pending_events[i].data.ptr = NULL;
break;
}
}
mux->num_descriptors--;
return rc;
}
static inline int timeval_to_ms(const struct timeval *t)
{
int ms = t->tv_sec * 1000;
ms += (t->tv_usec + 999) / 1000; //round upwards
return ms;
}
static int iomux_epoll_run(struct IOMux *mux_, struct timeval *timeout)
{
int i;
struct IOMuxEpoll *mux = mux_->instance;
int rc;
int timeout_ms;
int event_cnt;
if(mux->num_descriptors == 0 && timeout == NULL)
return 0;
//epoll takes the timeout in miliseconds
if(timeout)
timeout_ms = timeval_to_ms(timeout);
else
timeout_ms = -1;
rc = epoll_wait(mux->epoll_fd, mux->pending_events, EPOLL_WAIT_EVENTS, timeout_ms);
assert(rc >= 0);
if(rc < 0)
return errno;
mux->pending = rc;
event_cnt = iomux_timers_run(mux_); //process timers
if(rc == 0) //Just the timeout
return event_cnt;
for(i = 0; i < rc; i++) {
struct IOMuxFD *fd = mux->pending_events[i].data.ptr;
if(fd != NULL) { //calling _unregister from a callback could have removed it
unsigned int events;
events = epoll_2_mux_events(mux->pending_events[i].events);
assert(fd->callback != NULL);
fd->callback(mux_, fd, events);
//be sure not to use fd after the callback, it might been removed.
event_cnt++;
}
}
mux->pending = 0;
return event_cnt;
}
static void iomux_epoll_delete(struct IOMux *mux)
{
assert(mux != NULL && mux->instance != NULL);
if(mux != NULL && mux->instance != NULL) {
struct IOMuxEpoll *mux_epoll = mux->instance;
close(mux_epoll->epoll_fd);
free(mux_epoll);
mux->instance = NULL;
}
}
int iomux_epoll_init(struct IOMux *mux)
{
struct IOMuxEpoll *mux_epoll = calloc(1, sizeof *mux_epoll);
if(mux_epoll == NULL)
return ENOMEM;
mux_epoll->epoll_fd = epoll_create(128);
if(mux_epoll->epoll_fd == -1) {
free(mux_epoll);
return errno;
}
mux->instance = mux_epoll;
mux->run_impl = iomux_epoll_run;
mux->delete_impl = iomux_epoll_delete;
mux->register_fd_impl = iomux_epoll_register_fd;
mux->unregister_fd_impl = iomux_epoll_unregister_fd;
mux->update_events_impl = iomux_epoll_update_events;
return 0;
}
+139
View File
@@ -0,0 +1,139 @@
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <assert.h>
#include "iomux_impl.h"
//dispatchers for the IOMux implementations */
struct IOMux *iomux_create(enum IOMUX_TYPE type)
{
struct IOMux *mux = calloc(1, sizeof *mux);
int rc = -1;
switch(type) {
case IOMUX_TYPE_DEFAULT:
case IOMUX_TYPE_EPOLL:
rc = iomux_epoll_init(mux);
break;
case IOMUX_TYPE_SELECT:
rc = iomux_select_init(mux);
break;
}
if(rc != 0) {
//try fallback to select
rc = iomux_select_init(mux);
}
if(rc == 0) {
rc = gettimeofday(&mux->now, NULL);
assert(rc == 0);
uc_timers_init(&mux->timers);
} else {
free(mux);
mux = NULL;
}
return mux;
}
void iomux_delete(struct IOMux *mux)
{
mux->delete_impl(mux);
memset(mux, 0xfa, sizeof *mux);
free(mux);
}
//convert the difference between future and now
static inline void future_to_interval(struct timeval *future, const struct timeval *now, struct timeval *result)
{
if(timercmp(future, now, >)) {
timersub(future, now, result);
} else {
result->tv_sec = 0;
result->tv_usec = 0;
}
}
int iomux_run(struct IOMux *mux)
{
for(;;) {
int rc;
struct timeval first_timer;
struct timeval timeout;
struct timeval *timeoutp;;
int has_timers = 0;
rc = gettimeofday(&mux->now, NULL);
assert(rc == 0);
if(uc_timers_first(&mux->timers, &first_timer) == 0) {
future_to_interval(&first_timer, &mux->now, &timeout);
timeoutp = &timeout;
/* fprintf(stdout, "now %d %d future %d %d interval %d %d\n", mux->now.tv_sec, mux->now.tv_usec,
first_timer.tv_sec, first_timer.tv_usec,
timeout.tv_sec, timeout.tv_usec);
fflush(stdout);
*/
assert(timeout.tv_sec >= 0);
assert(timeout.tv_usec >= 0);
has_timers = 1;
} else {
timeoutp = NULL; //no timeout
}
rc = mux->run_impl(mux, timeoutp);
if(rc < 0)
return rc;
if(rc == 0 && !has_timers) //no more events, ever
return 0;
}
return 0;
}
int iomux_timers_run(struct IOMux *mux)
{
int event_cnt;
gettimeofday(&mux->now, NULL);
event_cnt = uc_timers_run(&mux->timers, &mux->now);
assert(event_cnt >= 0);
return event_cnt;
}
int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd)
{
assert(mux != NULL);
assert(fd != NULL);
assert(fd->callback != NULL);
return mux->register_fd_impl(mux, fd);
}
int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd)
{
assert(mux != NULL);
assert(fd != NULL);
return mux->unregister_fd_impl(mux, fd);
}
int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd)
{
assert(mux != NULL);
assert(fd != NULL);
assert(fd->callback != NULL);
return mux->update_events_impl(mux, fd);
}
struct UCTimers *iomux_get_timers(struct IOMux *mux)
{
return &mux->timers;
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef IO_MUX_IMPL_H_
#define IO_MUX_IMPL_H_
#include "iomux.h"
#include "ucore_timers.h"
/** struct for IOMux implementations */
struct IOMux {
/* TImer instance */
struct UCTimers timers;
/* Current time. Updated before calling run_impl, and updated
* by iomux_timers_run
*/
struct timeval now;
/* Used by mux implementations to hold their own data/instance */
void *instance;
/** Run one iteration of the mux.
* The mux implementation must honor the timeout, if given.
* The mux implementation must call iomux_timers_run after the
* polling has occured (or if it's polling times out)
*
* @mux The IOMux instance
* @timeout absolute time of a timeout - after which timers should run.
* If timeout is NULL, no timeout should be set on the poll.
*/
int (*run_impl)(struct IOMux *mux, struct timeval *timeout);
/* Deallocate the instance specific part of the IOMux */
void (*delete_impl)(struct IOMux *mux);
/** Register an IOMuxFD for events*/
int (*register_fd_impl)(struct IOMux *mux, struct IOMuxFD *fd);
/** Unregister an IOMuxFD */
int (*unregister_fd_impl)(struct IOMux *mux, struct IOMuxFD *fd);
/** Update an IOMuxFD (due to its events ('what') has changed*/
int (*update_events_impl)(struct IOMux *mux, struct IOMuxFD *fd);
};
int iomux_select_init(struct IOMux *mux);
int iomux_epoll_init(struct IOMux *mux);
int iomux_timers_run(struct IOMux *mux);
#endif
+212
View File
@@ -0,0 +1,212 @@
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include "iomux_impl.h"
#include "ucore_utils.h"
#define IOMUX_GROW_CHUNK (32)
struct IOMuxSelect {
fd_set master_read_set;
fd_set master_write_set;
struct IOMuxFD **descriptors; // array of pointers to the user IOMuxFD's
size_t alloc_descriptors; //allocated descriptors in 'descriptors'
size_t num_descriptors; //number of descriptors we're watching
size_t deleted_cnt; //used to rebuild the descriptors array
int max_fd; //keeps track of the max fd for select()
};
static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd);
//grows the descriptor array. We never shrink it.
static int iomux_select_grow(struct IOMuxSelect *mux)
{
void *tmp = realloc(mux->descriptors, (mux->num_descriptors + IOMUX_GROW_CHUNK) * sizeof *mux->descriptors);
assert(tmp != NULL);
if(tmp == NULL)
return ENOMEM;
mux->alloc_descriptors += IOMUX_GROW_CHUNK;
mux->descriptors = tmp;
return 0;
}
static void iomux_select_remove(struct IOMuxSelect *mux, size_t idx)
{
if(mux->num_descriptors > 1) {
//move last element into the empty slot
size_t last_idx = mux->num_descriptors - 1;
mux->descriptors[idx] = mux->descriptors[last_idx];
mux->descriptors[last_idx] = NULL;
}
mux->num_descriptors--;
}
static void iomux_select_rebuild(struct IOMuxSelect *mux)
{
size_t i;
mux->max_fd = -1;
for(i = 0; i < mux->num_descriptors; ) {
if(mux->descriptors[i] == NULL) {
iomux_select_remove(mux, i);
//a deleted fd slot needs to be rechecked, no i++ here
} else {
mux->max_fd = UC_MAX(mux->descriptors[i]->fd, mux->max_fd);
i++;
}
}
}
//sets or clears the events.
static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd)
{
struct IOMuxSelect *mux = mux_->instance;
if(fd->what & MUX_EV_READ)
FD_SET(fd->fd, &mux->master_read_set);
else
FD_CLR(fd->fd, &mux->master_read_set);
if(fd->what & MUX_EV_WRITE)
FD_SET(fd->fd, &mux->master_write_set);
else
FD_CLR(fd->fd, &mux->master_write_set);
return 0;
}
static int iomux_select_register_fd(struct IOMux *mux_, struct IOMuxFD *fd)
{
struct IOMuxSelect *mux = mux_->instance;
if(fd->what == 0 || fd->callback == NULL)
return EINVAL;
if(mux->num_descriptors == mux->alloc_descriptors) {
if(iomux_select_grow(mux) != 0)
return ENOMEM;
}
mux->descriptors[mux->num_descriptors] = fd;
mux->num_descriptors++;
iomux_select_update_events(mux_, fd);
mux->max_fd = UC_MAX(fd->fd, mux->max_fd);
return 0;
}
static int iomux_select_unregister_fd(struct IOMux *mux_, struct IOMuxFD *fd)
{
struct IOMuxSelect *mux = mux_->instance;
int rc = ENOENT;
size_t i;
for(i = 0; i < mux->num_descriptors; i++) {
if(fd == mux->descriptors[i]) {
int what = fd->what; //make sure we don't alter 'what' as seen from the user
fd->what &= ~MUX_EV_MASK;
iomux_select_update_events(mux_, fd);
mux->descriptors[i] = NULL; //set the slot to NULL, the event loop needs to rebuild it.
mux->deleted_cnt++;
fd->what = what;
rc = 0;
break;
}
}
return rc;
}
static int iomux_select_run(struct IOMux *mux_, struct timeval *timeout)
{
struct IOMuxSelect *mux = mux_->instance;
int rc;
size_t i;
int event_cnt = 0;
if(mux->deleted_cnt) {
iomux_select_rebuild(mux);
mux->deleted_cnt = 0;
}
if(mux->max_fd == -1 && timeout == NULL)
return 0;
fd_set read_set = mux->master_read_set;
fd_set write_set = mux->master_write_set;
rc = select(mux->max_fd + 1, &read_set, &write_set, NULL, timeout); //we can use timeout directly
assert(rc >= 0);
if(rc < 0)
return -1;
event_cnt = iomux_timers_run(mux_); //fire the timers
if(rc == 0) //Just the timeout
return event_cnt;
for(i = 0; rc >= 0 && i < mux->num_descriptors; i++) {
unsigned int events = 0;
if(mux->descriptors[i] == NULL) { //callback might have deleted it
continue;
}
if(FD_ISSET(mux->descriptors[i]->fd, &read_set)) {
events |= MUX_EV_READ;
}
if(FD_ISSET(mux->descriptors[i]->fd, &write_set)) {
events |= MUX_EV_WRITE;
}
if(events) {
assert(mux->descriptors[i]->callback != NULL);
mux->descriptors[i]->callback(mux_, mux->descriptors[i], events);
rc--;
event_cnt++;
}
}
return event_cnt;
}
static void iomux_select_delete(struct IOMux *mux)
{
if(mux != NULL && mux->instance != NULL) {
struct IOMuxSelect *mux_select = mux->instance;
free(mux_select->descriptors);
mux_select->descriptors = NULL;
free(mux_select);
mux->instance = NULL;
}
}
int iomux_select_init(struct IOMux *mux)
{
struct IOMuxSelect *mux_select = calloc(1, sizeof *mux_select);
if(mux_select == NULL)
return ENOMEM;
mux_select->max_fd = -1;
mux->instance = mux_select;
mux->run_impl = iomux_select_run;
mux->delete_impl = iomux_select_delete;
mux->register_fd_impl = iomux_select_register_fd;
mux->unregister_fd_impl = iomux_select_unregister_fd;
mux->update_events_impl = iomux_select_update_events;
return 0;
}
+741
View File
@@ -0,0 +1,741 @@
/* $NetBSD: tree.h,v 1.16 2008/03/21 13:07:15 ad Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) do { \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) (void)(x)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
attr struct type *name##_RB_INSERT(struct name *, struct type *); \
attr struct type *name##_RB_FIND(struct name *, struct type *); \
attr struct type *name##_RB_NFIND(struct name *, struct type *); \
attr struct type *name##_RB_NEXT(struct type *); \
attr struct type *name##_RB_PREV(struct type *); \
attr struct type *name##_RB_MINMAX(struct name *, int); \
\
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp,)
#define RB_GENERATE_STATIC(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) != NULL && \
RB_COLOR(parent, field) == RB_RED) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
} \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
} \
\
attr void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)) \
!= NULL) \
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_LEFT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)) \
!= NULL) \
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_RIGHT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \
} \
\
attr struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field)) != NULL) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (RB_PARENT(old, field)) { \
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
RB_LEFT(RB_PARENT(old, field), field) = elm;\
else \
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
RB_AUGMENT(RB_PARENT(old, field)); \
} else \
RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field)) != NULL); \
} \
goto color; \
} \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
attr struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
attr struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
/* Finds the first node greater than or equal to the search key */ \
attr struct type * \
name##_RB_NFIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *res = NULL; \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) { \
res = tmp; \
tmp = RB_LEFT(tmp, field); \
} \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (res); \
} \
\
/* ARGSUSED */ \
attr struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
/* ARGSUSED */ \
attr struct type * \
name##_RB_PREV(struct type *elm) \
{ \
if (RB_LEFT(elm, field)) { \
elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
attr struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_REVERSE(x, name, head) \
for ((x) = RB_MAX(name, head); \
(x) != NULL; \
(x) = name##_RB_PREV(x))
#endif /* _SYS_TREE_H_ */
+14
View File
@@ -0,0 +1,14 @@
#include <execinfo.h>
#define MAX_BACKTRACE_SYMBOLS 96
void uc_backtrace_fd(int fd)
{
void *buffer[MAX_BACKTRACE_SYMBOLS];
int ptrs;
ptrs = backtrace(buffer, MAX_BACKTRACE_SYMBOLS);
backtrace_symbols_fd(buffer, ptrs, fd);
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef UC_BACKTRACE_H_
#define UC_BACKTRACE_H_
#define UC_BACTRACE_STDERR uc_backtrace_fd(3)
void uc_backtrace_fd(int fd);
#endif
+52
View File
@@ -0,0 +1,52 @@
#include <stdint.h>
#include "ucore_string.h"
static const uint8_t basecode[128] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff
};
#define deccode(c) ((c > 127) ? 0xff : basecode[(c)])
size_t
uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result)
{
size_t i = 0, j = 0, pad;
uint8_t c[4];
while ((i + 3) < len) {
pad = 0;
c[0] = deccode(data[i ]); pad += (c[0] == 0xff);
c[1] = deccode(data[i+1]); pad += (c[1] == 0xff);
c[2] = deccode(data[i+2]); pad += (c[2] == 0xff);
c[3] = deccode(data[i+3]); pad += (c[3] == 0xff);
switch (pad) {
case 1:
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2);
result[j] = (c[2] & 0x03) << 6;
break;
case 2:
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
result[j] = (c[1] & 0x0f) << 4;
break;
default:
result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4);
result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2);
result[j++] = ((c[2] & 0x03) << 6) | (c[3] & 0x3f);
}
i += 4;
}
return j;
}
+43
View File
@@ -0,0 +1,43 @@
#include <stdint.h>
#include <stdlib.h>
#include "ucore_string.h"
static const char basecode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#define PAD '='
size_t
uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result)
{
size_t i = 0, j = 0;
size_t pad;
while (i < len) {
pad = 3 - (len - i);
switch(pad) {
case 2:
result[j] = basecode[data[i]>>2];
result[j+1] = basecode[(data[i] & 0x03) << 4];
result[j+2] = PAD;
result[j+3] = PAD;
break;
case 3:
result[j ] = basecode[data[i]>>2];
result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)];
result[j+2] = basecode[(data[i+1] & 0x0f) << 2];
result[j+3] = PAD;
break;
default:
result[j ] = basecode[data[i]>>2];
result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)];
result[j+2] = basecode[((data[i+1] & 0x0f) << 2) | ((data[i+2] & 0xc0) >> 6)];
result[j+3] = basecode[data[i+2] & 0x3f];
break;
}
j += 4;
i += 3;
}
return j;
}
+55
View File
@@ -0,0 +1,55 @@
#include <ctype.h>
#include <stdint.h>
#include <stddef.h>
#include "ucore_string.h"
size_t
uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler)
{
unsigned char *bcdp = bcdout;
int shift = 0;
*bcdp = 0;
for(; *ascii; ascii++) {
if(*ascii < '0' || *ascii > '9') {
continue;
}
*bcdp |= (*ascii - '0') << shift;
if(shift) {
bcdp++;
*bcdp = 0;
}
shift = 4 - shift;
}
if(shift) {
*bcdp |= (filler & 0xf) << 4;
bcdp++;
}
return bcdp - bcdout;
}
static const char hex[] = "0123456789ABCDEF";
size_t
uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout)
{
size_t i;
size_t idx = 0;
for(i = 0; i < bcdlen; i++) {
asciiout[idx] = hex[bcd[i] & 0xf];
idx++;
asciiout[idx] = hex[(bcd[i] & 0xf0) >> 4];
idx++;
}
asciiout[idx] = 0;
return idx;
}
+126
View File
@@ -0,0 +1,126 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include "ucore_bitvec.h"
#ifdef __GNUC__
#define likely(expr) __builtin_expect((expr), 1)
#define unlikely(expr) __builtin_expect((expr), 0)
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif
static inline int bit_index(int b)
{
return b / (sizeof(unsigned long) * CHAR_BIT);
}
static inline int bit_offset(int b)
{
return b % (sizeof(unsigned long) * CHAR_BIT);
}
struct bitvec *bitvec_new(size_t nbits)
{
struct bitvec *v = malloc(sizeof *v);
if(v == NULL)
return NULL;
v->vec_len = BITVEC_VEC_LEN(nbits);
v->vec = malloc(v->vec_len * sizeof(unsigned long));
if(v->vec == NULL) {
free(v);
return NULL;
}
clear_all(v);
return v;
}
void bitvec_free(struct bitvec *v)
{
if(v) {
free(v->vec);
free(v);
}
}
void clear_bit(struct bitvec *v,int b)
{
v->vec[bit_index(b)] &= ~(1UL << (bit_offset(b)));
}
int get_bit(const struct bitvec *v,int b)
{
return !!(v->vec[bit_index(b)] & (1UL << bit_offset(b)));
}
void set_bit(struct bitvec *v,int b)
{
v->vec[bit_index(b)] |= 1UL << (bit_offset(b));
}
void set_bit_s(struct bitvec *v,int b)
{
size_t idx = (size_t)bit_index(b);
assert(b >= 0);
assert(v->vec_len > (size_t)idx);
if(likely(idx < v->vec_len))
v->vec[idx] |= 1UL << (bit_offset(b));
}
void clear_bit_s(struct bitvec *v,int b)
{
size_t idx = (size_t)bit_index(b);
assert(b >= 0);
assert(v->vec_len > (size_t)idx);
if(likely(idx < v->vec_len))
v->vec[idx] &= ~(1UL << (bit_offset(b)));
}
int get_bit_s(const struct bitvec *v,int b)
{
size_t idx = (size_t)bit_index(b);
assert(b >= 0);
assert(v->vec_len > (size_t)idx);
if(likely(idx < v->vec_len))
return !!(v->vec[idx] & (1UL << bit_offset(b)));
else
return 0;
}
void set_bits_from_array(struct bitvec *v,char *array,size_t array_len)
{
size_t i;
for(i = 0; i < array_len; i++) {
size_t idx = (size_t)bit_index(array_len);
if(unlikely(idx >= v->vec_len))
break;
if(array[i])
set_bit(v,i);
else
clear_bit(v,i);
}
}
void clear_all(struct bitvec *v)
{
memset(v->vec,0, v->vec_len * sizeof(unsigned long));
}
void set_all(struct bitvec *v)
{
memset(v->vec,0xff,v->vec_len * sizeof(unsigned long));
}
+81
View File
@@ -0,0 +1,81 @@
#ifndef BITEVEC_H_
#define BITEVEC_H_
#ifdef __cplusplus
extern "C" {
#endif
struct bitvec {
//storage for the bits
unsigned long *vec;
//length of the above vec. (Not the number of bits !)
size_t vec_len;
};
/**
* Evaluates the length required for a bitvec to store nbit bits.
*/
#define BITVEC_VEC_LEN(nbits) ((nbits/(sizeof(unsigned long)*CHAR_BIT)) + (nbits % (sizeof(unsigned long)*CHAR_BIT) == 0 ? 0 : 1))
/**
* Use as :
* unsigned long v[10];
* struct bitvec v = BITVEC_STATIC_INIT(v);
*/
#define BITVEC_STATIC_INIT(vec_data)\
{\
vec_data,\
sizeof vec_data/sizeof vec_data[0]}
/**
* Returns a newly malloced bitvec, capable of storing at least nbits bits
* All bits are initially zero.
*
*/
struct bitvec *bitvec_new(size_t nbits);
/** free a bitvec previously allocated by bitvec_new
*/
void bitvec_free(struct bitvec *v);
//Note that accessing a bit beyond the nbits originally initialized
//for the given bitvec is undedefined
/** Sets bit no. b */
void set_bit(struct bitvec *v,int b);
/** Clears bit no. b*/
void clear_bit(struct bitvec *v,int b);
/** Gets the current value (0 or 1) of bit no. b*/
int get_bit(const struct bitvec *v,int b);
/** Sets all bits to zero */
void clear_all(struct bitvec *v);
/** Sets all bits to one */
void set_all(struct bitvec *v);
/** Initialize bits from a array of ints, each array element maps to one bit.
* The bits are initialized from the int array so zero maps to zero and non-zero maps to one.
* e..g to set the 5 first bits, to 01110:
* int a[] = {0,1,1,1,0};
* set_bits_from_array(v,a,5);
* */
void set_bits_from_array(struct bitvec *v,char *array,size_t array_len);
// The _s ("secure") versions does boundary checking and assert() if they
// try to access a bit out of bounds.
void set_bit_s(struct bitvec *v,int b);
void clear_bit_s(struct bitvec *v,int b);
int get_bit_s(const struct bitvec *v,int b);
#ifdef __cplusplus
}
#endif
#endif
+77
View File
@@ -0,0 +1,77 @@
#include <stdlib.h>
#include <string.h>
#include "ucore_buffer.h"
GBuf*
uc_new_gbuf(size_t initsz)
{
GBuf *p;
p = malloc(sizeof *p);
if(p == NULL)
return NULL;
p->used = 0;
p->len = initsz;
p->buf = NULL;
p->ref_cnt = 1;
if(initsz != 0 && (p->buf = malloc(initsz)) == NULL) {
free(p);
return NULL;
}
return p;
}
void
uc_gbuf_ref(GBuf *buf)
{
buf->ref_cnt++;
}
void
uc_gbuf_unref(GBuf *buf)
{
buf->ref_cnt--;
if(buf->ref_cnt == 0) {
free(buf->buf);
free(buf);
}
}
int
uc_gbuf_append(GBuf *buf,void *data,size_t len)
{
unsigned char *d = data;
unsigned char *gbuf;
if(buf->len - buf->used < len)
if(uc_grow_gbuf(buf, len + len/2))
return -1;
gbuf = buf->buf;
memcpy(gbuf + buf->used,d,len);
buf->used += len;
return 0;
}
int
uc_grow_gbuf(GBuf *buf, size_t addlen)
{
void *tmp;
size_t newsz;
newsz = buf->len + addlen;
tmp = realloc(buf->buf,newsz);
if(tmp == NULL)
return -1;
buf->buf = tmp;
buf->len = newsz;
return 0;
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef UCORE_BUFFER_H_
#define UCORE_BUFFER_H_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct GBuf GBuf;
struct GBuf {
size_t len;
size_t used;
size_t ref_cnt;
void *buf;
};
GBuf*
uc_new_gbuf(size_t initsz);
void
uc_gbuf_ref(GBuf *buf);
void
uc_gbuf_unref(GBuf *buf);
int
uc_gbuf_append(GBuf *buf,void *data,size_t len);
int
uc_grow_gbuf(GBuf *buf, size_t addlen);
#ifdef __cplusplus
}
#endif
#endif
+71
View File
@@ -0,0 +1,71 @@
#include "ucore_hash.h"
static const uint32_t crc32_table[256] = {
0x0,0x4C11DB7,0x9823B6E,0xD4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,0x2608EDB8,0x22C9F00F,0x2F8AD6D6,
0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD,0x4C11DB70,0x48D0C6C7,0x4593E01E,0x4152FDA9,0x5F15ADAC,
0x5BD4B01B,0x569796C2,0x52568B75,0x6A1936C8,0x6ED82B7F,0x639B0DA6,0x675A1011,0x791D4014,0x7DDC5DA3,0x709F7B7A,
0x745E66CD,0x9823B6E0,0x9CE2AB57,0x91A18D8E,0x95609039,0x8B27C03C,0x8FE6DD8B,0x82A5FB52,0x8664E6E5,0xBE2B5B58,
0xBAEA46EF,0xB7A96036,0xB3687D81,0xAD2F2D84,0xA9EE3033,0xA4AD16EA,0xA06C0B5D,0xD4326D90,0xD0F37027,0xDDB056FE,
0xD9714B49,0xC7361B4C,0xC3F706FB,0xCEB42022,0xCA753D95,0xF23A8028,0xF6FB9D9F,0xFBB8BB46,0xFF79A6F1,0xE13EF6F4,
0xE5FFEB43,0xE8BCCD9A,0xEC7DD02D,0x34867077,0x30476DC0,0x3D044B19,0x39C556AE,0x278206AB,0x23431B1C,0x2E003DC5,
0x2AC12072,0x128E9DCF,0x164F8078,0x1B0CA6A1,0x1FCDBB16,0x18AEB13,0x54BF6A4,0x808D07D,0xCC9CDCA,0x7897AB07,
0x7C56B6B0,0x71159069,0x75D48DDE,0x6B93DDDB,0x6F52C06C,0x6211E6B5,0x66D0FB02,0x5E9F46BF,0x5A5E5B08,0x571D7DD1,
0x53DC6066,0x4D9B3063,0x495A2DD4,0x44190B0D,0x40D816BA,0xACA5C697,0xA864DB20,0xA527FDF9,0xA1E6E04E,0xBFA1B04B,
0xBB60ADFC,0xB6238B25,0xB2E29692,0x8AAD2B2F,0x8E6C3698,0x832F1041,0x87EE0DF6,0x99A95DF3,0x9D684044,0x902B669D,
0x94EA7B2A,0xE0B41DE7,0xE4750050,0xE9362689,0xEDF73B3E,0xF3B06B3B,0xF771768C,0xFA325055,0xFEF34DE2,0xC6BCF05F,
0xC27DEDE8,0xCF3ECB31,0xCBFFD686,0xD5B88683,0xD1799B34,0xDC3ABDED,0xD8FBA05A,0x690CE0EE,0x6DCDFD59,0x608EDB80,
0x644FC637,0x7A089632,0x7EC98B85,0x738AAD5C,0x774BB0EB,0x4F040D56,0x4BC510E1,0x46863638,0x42472B8F,0x5C007B8A,
0x58C1663D,0x558240E4,0x51435D53,0x251D3B9E,0x21DC2629,0x2C9F00F0,0x285E1D47,0x36194D42,0x32D850F5,0x3F9B762C,
0x3B5A6B9B,0x315D626,0x7D4CB91,0xA97ED48,0xE56F0FF,0x1011A0FA,0x14D0BD4D,0x19939B94,0x1D528623,0xF12F560E,
0xF5EE4BB9,0xF8AD6D60,0xFC6C70D7,0xE22B20D2,0xE6EA3D65,0xEBA91BBC,0xEF68060B,0xD727BBB6,0xD3E6A601,0xDEA580D8,
0xDA649D6F,0xC423CD6A,0xC0E2D0DD,0xCDA1F604,0xC960EBB3,0xBD3E8D7E,0xB9FF90C9,0xB4BCB610,0xB07DABA7,0xAE3AFBA2,
0xAAFBE615,0xA7B8C0CC,0xA379DD7B,0x9B3660C6,0x9FF77D71,0x92B45BA8,0x9675461F,0x8832161A,0x8CF30BAD,0x81B02D74,
0x857130C3,0x5D8A9099,0x594B8D2E,0x5408ABF7,0x50C9B640,0x4E8EE645,0x4A4FFBF2,0x470CDD2B,0x43CDC09C,0x7B827D21,
0x7F436096,0x7200464F,0x76C15BF8,0x68860BFD,0x6C47164A,0x61043093,0x65C52D24,0x119B4BE9,0x155A565E,0x18197087,
0x1CD86D30,0x29F3D35,0x65E2082,0xB1D065B,0xFDC1BEC,0x3793A651,0x3352BBE6,0x3E119D3F,0x3AD08088,0x2497D08D,
0x2056CD3A,0x2D15EBE3,0x29D4F654,0xC5A92679,0xC1683BCE,0xCC2B1D17,0xC8EA00A0,0xD6AD50A5,0xD26C4D12,0xDF2F6BCB,
0xDBEE767C,0xE3A1CBC1,0xE760D676,0xEA23F0AF,0xEEE2ED18,0xF0A5BD1D,0xF464A0AA,0xF9278673,0xFDE69BC4,0x89B8FD09,
0x8D79E0BE,0x803AC667,0x84FBDBD0,0x9ABC8BD5,0x9E7D9662,0x933EB0BB,0x97FFAD0C,0xAFB010B1,0xAB710D06,0xA6322BDF,
0xA2F33668,0xBCB4666D,0xB8757BDA,0xB5365D03,0xB1F740B4};
uint32_t
uc_crc32(const uint8_t *buf, size_t len)
{
const uint8_t *p;
uint32_t crc;
crc = 0xffffffff; /* preload shift register, per CRC-32 spec */
for (p = buf; len > 0; ++p, --len)
crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *p];
return ~crc; /* transmit complement, per CRC-32 spec */
}
/* the above table is built with this:
#define CRC32_POLY 0x04c11db7 // AUTODIN II, Ethernet, & FDDI
init_crc32()
{
int i, j;
unsigned long c;
for (i = 0; i < 256; ++i) {
for (c = i << 24, j = 8; j > 0; --j)
c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1);
crc32_table[i] = c;
}
}
#include <stdio.h>
int main()
{
int i;
init_crc32();
for(i = 0; i < 256; i++) {
printf("0x%X,",crc32_table[i]);
if(i%10 == 0)
putchar('\n');
}
return 0;
}
*/
+18
View File
@@ -0,0 +1,18 @@
int
uc_day_of_week(int day, int month, int year)
{
int cent;
/* adjust months so February is the last one */
month -= 2;
if (month < 1) {
month += 12;
--year;
}
/* split by century */
cent = year / 100;
year %= 100;
return ((26 * month - 2) / 10 + day + year
+ year / 4 + cent / 4 + 5 * cent) % 7;
}
+13
View File
@@ -0,0 +1,13 @@
#include "ucore_hash.h"
uint32_t
uc_djbhash(const char *str)
{
uint32_t hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
+20
View File
@@ -0,0 +1,20 @@
#include "ucore_hash.h"
uint32_t
uc_elfhash(const char *str, uint32_t len)
{
uint32_t hash = 0;
uint32_t x = 0;
uint32_t i = 0;
for (i = 0; i < len; str++, i++) {
hash = (hash << 4) + (*str);
if ((x = hash & 0xF0000000L) != 0) {
hash ^= (x >> 24);
hash &= ~x;
}
}
return hash;
}
+13
View File
@@ -0,0 +1,13 @@
#include "ucore_math.h"
uint32_t
uc_gcd_32(uint32_t a, uint32_t b)
{
while(b != 0) {
uint32_t t = b;
b = a%b;
a = t;
}
return a;
}
+13
View File
@@ -0,0 +1,13 @@
#include "ucore_math.h"
uint64_t
uc_gcd_64(uint64_t a, uint64_t b)
{
while(b != 0) {
uint64_t t = b;
b = a%b;
a = t;
}
return a;
}
+38
View File
@@ -0,0 +1,38 @@
#include <string.h>
#include "ucore_string.h"
int
getfields(char *str, char **args, int max, int mflag, const char *set)
{
char r;
int intok, narg;
if(max <= 0)
return 0;
narg = 0;
args[narg] = str;
if(!mflag)
narg++;
intok = 0;
for(;; str++) {
r = *str;
if(r == 0)
break;
if(strchr(set, r)) {
if(narg >= max)
break;
*str = 0;
intok = 0;
args[narg] = str + 1;
if(!mflag)
narg++;
} else {
if(!intok && mflag)
narg++;
intok = 1;
}
}
return narg;
}
+39
View File
@@ -0,0 +1,39 @@
#ifndef UCORE_HASH_H_
#define UCORE_HASH_H_
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
uint32_t
uc_crc32(const uint8_t *buf, size_t len);
uint32_t
uc_djbhash(const char *str);
unsigned int
uc_elfhash(const char *str, unsigned int len);
uint64_t
uc_hash64shift(uint64_t key);
uint32_t
uc_hashuint(uint32_t a);
uint32_t
uc_murmurmash2(const void *key, int len, uint32_t seed );
uint32_t
uc_pjwhash(const char *str,size_t len);
uint32_t
sax_hash(void *key, size_t len);
#ifdef __cplusplus
}
#endif
#endif
+16
View File
@@ -0,0 +1,16 @@
#include <stdint.h>
#include "ucore_hash.h"
uint64_t
uc_hash64shift(uint64_t key)
{
key = (~key) + (key << 21); // key = (key << 21) - key - 1;
key = key ^ (key >> 24);
key = (key + (key << 3)) + (key << 8); // key * 265
key = key ^ (key >> 14);
key = (key + (key << 2)) + (key << 4); // key * 21
key = key ^ (key >> 28);
key = key + (key << 31);
return key;
}
+13
View File
@@ -0,0 +1,13 @@
#include "ucore_hash.h"
uint32_t
uc_hashint(uint32_t a)
{
a = (a ^ 61) ^ (a >> 16);
a = a + (a << 3);
a = a ^ (a >> 4);
a = a * 0x27d4eb2d;
a = a ^ (a >> 15);
return a;
}
+41
View File
@@ -0,0 +1,41 @@
#include <string.h>
#include "ucore_heapsort.h"
static void
uc_sift(unsigned char *base, size_t start, size_t count, size_t width,
uc_hs_cmp cmp)
{
size_t root = start, child;
while ((root * 2 + 1) < count) {
child = root * 2 + 1;
if (child < (count - 1)
&& cmp(&base[child * width], &base[(child + 1) * width]) < 0)
child++;
if (cmp(&base[root * width], &base[child * width]) < 0) {
memcpy(base + root * width, base + child * width, width);
root = child;
} else
return;
}
}
void
uc_heapsort(void *base_, size_t count, size_t width,
uc_hs_cmp cmp)
{
int start = count / 2 - 1, end = count - 1;
unsigned char *base = base_;
while (start >= 0) {
uc_sift(base, start, count, width, cmp);
start--;
}
while (end > 0) {
memcpy(base + end * width, base, width);
uc_sift(base, 0, end, width, cmp);
end--;
}
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef UCORE_HEAPSORT_H_
#define UCORE_HEAPSORT_H_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
///compare function. Needs only to return < 0 if
//the first element is less than the second
typedef int (*uc_hs_cmp)(const void *, const void *);
void
uc_heapsort(void *base, size_t count, size_t width,
uc_hs_cmp cmp);
#ifdef __cplusplus
}
#endif
#endif
+77
View File
@@ -0,0 +1,77 @@
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include "ucore_string.h"
static const char hx_chars[] = "0123456789ABCDEF" ;
char*
uc_hex_encode(const uint8_t *in, size_t len, char *out)
{
unsigned int i, t, hn, ln;
for (i = 0, t = 0; i < len; ++i,t+=2) {
hn = (in[i] & 0xF0) >> 4 ;
ln = in[i] & 0x0F ;
out[t] = hx_chars[hn];
out[t+1] = hx_chars[ln];
}
out[t] = 0;
return out;
}
char*
uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, char *delim)
{
unsigned int i;
char *outp = out;
out[0] = 0;
for (i = 0; i < inlen && outlen > 0; i++) {
int rc = snprintf(outp, outlen, "%02X%s", in[i], delim);
if(rc <= 0)
break;
outp += rc;
outlen -= rc;
}
return outp;
}
/* ASCII only */
static inline int char_to_bin(char c)
{
if(c >='0' && c <='9')
return c - '0';
else if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
else if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
return -1;
}
uint8_t*
uc_hex_decode(const char *in, size_t maxlen,uint8_t *out)
{
size_t i, t;
for (t = 0,i = 0; i + 1 < maxlen && in[i] && in[i + 1]; i+=2 , ++t) {
int hn, ln;
hn = char_to_bin(in[i]);
ln = char_to_bin(in[i + 1]);
if(hn == -1 || ln == -1)
return NULL;
out[t] = (hn << 4 ) | ln;
}
return &out[t];
}
+24
View File
@@ -0,0 +1,24 @@
#include <stdio.h>
#include <inttypes.h>
#include "ucore_string.h"
char *
uc_human_bytesz(uint64_t bytes, char *result, size_t result_len)
{
if(bytes < 1000) {
snprintf(result, result_len, "%" PRIu64 " b", bytes);
} else if (bytes < 1000000) {
snprintf(result, result_len, "%.2f kB", bytes/1000.0);
} else if (bytes < 1000000000ULL) {
snprintf(result, result_len, "%.2f MB", bytes/1000000.0);
} else if (bytes < 1000000000000ULL) {
snprintf(result, result_len, "%.2f GB", bytes/1000000000.0);
} else if (bytes < 1000000000000000ULL) {
snprintf(result, result_len, "%.2f TB", bytes/1000000000000.0);
} else {
snprintf(result, result_len, "%.2f PB", bytes/1000000000000000.0);
}
return result;
}
+334
View File
@@ -0,0 +1,334 @@
#include <pthread.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <sys/queue.h>
#include "ucore_logging.h"
struct uc_log_destination {
SLIST_ENTRY(uc_log_destination) entry;
enum UC_LOG_DESTINATION dest_type;
int log_level;
int log_location;
union {
//for syslog
struct {
const char *ident;
int facility;
} syslog;
//for stderr and files
struct {
FILE* file;
char *file_name; //NULL for stderr destinaton
} file;
} type;
};
struct uc_log_args {
struct uc_log_destination *dest;
const struct uc_log_module *module;
int log_level;
const char *file;
int line;
};
//Global lock for the logging system, as logging could be performed from any thread. All operations must grab
//this lock before accessing any the global data.
static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
static struct uc_log_modules modules;
static const struct uc_log_module unknown_module = {
.id = -1,
.short_name = "UNKNOWN",
.long_name = "Unknown log module",
.log_level = UC_LL_DEBUG,
};
static SLIST_HEAD(, uc_log_destination) destinations;
inline const char *uc_ll_2_str(enum UC_LOG_LEVEL l)
{
switch(l) {
case UC_LL_NONE:
return "NONE";
case UC_LL_DEBUG:
return "DEBUG";
case UC_LL_INFO:
return "INFO";
case UC_LL_WARNING:
return "WARNING";
case UC_LL_ERROR:
return "ERROR";
}
return "";
}
static inline int uc_ll_2_syslog(enum UC_LOG_LEVEL l)
{
switch(l) {
case UC_LL_NONE:
case UC_LL_DEBUG:
return LOG_DEBUG;
case UC_LL_INFO:
return LOG_INFO;
case UC_LL_WARNING:
return LOG_WARNING;
case UC_LL_ERROR:
return LOG_ERR;
}
return LOG_INFO;
}
struct uc_log_destination *uc_log_new_stderr(int log_level, int log_location)
{
struct uc_log_destination *dest = calloc(1, sizeof *dest);
if(dest == NULL)
return NULL;
dest->dest_type = UC_LDEST_STDERR;
dest->type.file.file = stderr;
dest->log_level = log_level;;
dest->log_location = log_location;
return dest;
}
struct uc_log_destination *uc_log_new_syslog(const char *ident, int facility, int log_level, int log_location)
{
struct uc_log_destination *dest = calloc(1, sizeof *dest);
if(dest == NULL)
return NULL;
openlog(ident, LOG_NDELAY | LOG_PID, facility);
dest->dest_type = UC_LDEST_SYSLOG;
dest->type.syslog.ident = ident;
dest->type.syslog.facility = facility;
dest->log_level = log_level;;
dest->log_location = log_location;
return dest;
}
struct uc_log_destination *uc_log_new_file(const char *filename, int log_level, int log_location)
{
struct uc_log_destination *dest = calloc(1, sizeof *dest);
FILE *f;
char *name;
if(dest == NULL)
return NULL;
name = strdup(filename);
if(name == NULL) {
free(dest);
return NULL;
}
f = fopen(filename, "a");
if(f == NULL) {
free(name);
free(dest);
return NULL;
}
dest->dest_type = UC_LDEST_FILE;
dest->type.file.file = f;
dest->type.file.file_name = name;
dest->log_level = log_level;;
dest->log_location = log_location;
return dest;
}
void uc_log_add_destination(struct uc_log_destination *dest)
{
struct uc_log_destination *it;
pthread_mutex_lock(&log_lock);
//make sure the destination isn't added twice.
SLIST_FOREACH(it, &destinations, entry) {
if(dest == it)
break;
}
//add if it isn't already in the list
if(it == NULL) {
SLIST_INSERT_HEAD(&destinations, dest, entry);
}
pthread_mutex_unlock(&log_lock);
}
void uc_log_remove_destination(struct uc_log_destination *dest)
{
pthread_mutex_lock(&log_lock);
SLIST_REMOVE(&destinations, dest, uc_log_destination, entry);
pthread_mutex_unlock(&log_lock);
}
int uc_log_reopen_files(void)
{
struct uc_log_destination *dest;
int rc = 0;
pthread_mutex_lock(&log_lock);
SLIST_FOREACH(dest, &destinations, entry) {
if(dest->dest_type == UC_LDEST_FILE) {
if(dest->type.file.file != NULL) {
fclose(dest->type.file.file);
dest->type.file.file = NULL;
}
if(dest->type.file.file_name != NULL) {
dest->type.file.file = fopen(dest->type.file.file_name, "a");
if(dest->type.file.file == NULL)
rc = errno;
}
}
}
pthread_mutex_unlock(&log_lock);
return rc;
}
void uc_log_init(struct uc_log_modules *user_modules)
{
modules = *user_modules;
}
int uc_log_module_set_loglevel(int module, enum UC_LOG_LEVEL level)
{
int rc = -1;
int i;
pthread_mutex_lock(&log_lock);
for(i = 0; i < modules.cnt; i++) {
if(modules.mods[i].id == module) {
modules.mods[i].log_level = level;
rc = 0;
break;
}
}
pthread_mutex_unlock(&log_lock);
return rc;
}
static inline void uc_vlog_internal(const struct uc_log_args *args, const char *fmt, va_list ap)
{
struct uc_log_destination *dest = args->dest;
if(dest->dest_type != UC_LDEST_SYSLOG && dest->type.file.file != NULL) {
char time_buf[48];
time_t now;
struct tm tmbuf;
now = time(NULL);
localtime_r(&now, &tmbuf);
strftime(time_buf, sizeof time_buf, "%d %b %Y %H:%M:%S %Z", &tmbuf);
if(dest->log_location) {
fprintf(dest->type.file.file, "[%s] %s %s:%d [%s] : ", uc_ll_2_str(args->log_level),
time_buf, args->file, args->line, args->module->short_name);
} else {
fprintf(dest->type.file.file, "[%s] %s [%s]: ",
uc_ll_2_str(args->log_level), time_buf, args->module->short_name);
}
vfprintf(dest->type.file.file, fmt, ap);
fflush(dest->type.file.file); //strictly not needed for stderr
// though stderr could be redirected to a file
} else if(dest->dest_type == UC_LDEST_SYSLOG) {
int pri = uc_ll_2_syslog(args->log_level);
//go via a buffer as we must do just 1 syslog call
char buf[4096];
int len = 0;
if(dest->log_location) {
len = snprintf(buf, sizeof buf, "%s:%d ", args->file, args->line);
}
len += snprintf(&buf[len], sizeof buf - (size_t)len, "[%s] ", args->module->short_name);
vsnprintf(&buf[len], sizeof buf - (size_t)len, fmt, ap);
syslog(pri, "%s", buf);
}
}
void uc_logf(int log_level, int module, const char *file, int line, const char *fmt, ...)
{
va_list ap;
struct uc_log_destination *dest;
const struct uc_log_module *log_module;
va_start(ap, fmt);
pthread_mutex_lock(&log_lock);
//Find the module doign the logging, or use the unknown module -
//the latter would indicate a bug somewhere in the application as it should
//always specify a known module
if(module >= 0 && module < modules.cnt)
log_module = &modules.mods[module];
else
log_module = &unknown_module;
//Check if the module should not be logged
if(log_level < log_module->log_level)
goto out;
//do logging for each destination
SLIST_FOREACH(dest, &destinations, entry) {
va_list apc;
if(log_level >= dest->log_level) {
const struct uc_log_args args = {
.dest = dest,
.module = log_module,
.log_level = log_level,
.file = file,
.line = line,
};
//log func will mess with the va_list,
//so make a copy
va_copy(apc, ap);
uc_vlog_internal(&args, fmt, apc);
va_end(apc);
}
}
out:
pthread_mutex_unlock(&log_lock);
va_end(ap);
}
+62
View File
@@ -0,0 +1,62 @@
#ifndef UCORE_LOGGING_H_
#define UCORE_LOGGING_H_
enum UC_LOG_LEVEL {
UC_LL_NONE = 0,
UC_LL_DEBUG = 1,
UC_LL_INFO = 3,
UC_LL_WARNING = 5,
UC_LL_ERROR = 7,
};
enum UC_LOG_DESTINATION {
UC_LDEST_SYSLOG,
UC_LDEST_STDERR,
UC_LDEST_FILE,
};
struct uc_log_module {
int id;
const char *short_name;
const char *long_name;
int log_level;
};
struct uc_log_modules {
struct uc_log_module *mods;
int cnt;
};
struct uc_log_destination;
const char *uc_ll_2_str(enum UC_LOG_LEVEL l);
struct uc_log_destination *uc_log_new_stderr(int log_level, int log_location);
struct uc_log_destination *uc_log_new_syslog(const char *ident, int facility, int log_level, int log_location);
struct uc_log_destination *uc_log_new_file(const char *filename, int log_level, int log_location);
void uc_log_add_destination(struct uc_log_destination *dest);
void uc_log_remove_destination(struct uc_log_destination *dest);
int uc_log_module_set_loglevel(int module, enum UC_LOG_LEVEL level);
int uc_log_reopen_files(void);
void uc_log_init(struct uc_log_modules *user_modules);
void uc_logf(int log_level, int module, const char *file, int line, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
#ifdef DEBUG
# define UC_DEBUGF(mod, fmt, ...) uc_logf(UC_LL_DEBUG, mod, __FILE__, __LINE__, fmt, ## __VA_ARGS__)
#else
# define UC_DEBUGF(mod, fmt, ...)
#endif
#define UC_LOGF(lvl, mod, fmt, ...) uc_logf(lvl, mod, __FILE__, __LINE__, fmt, ## __VA_ARGS__)
#endif
+39
View File
@@ -0,0 +1,39 @@
#ifndef UCORE_MATH_H_
#define UCORE_MATH_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
uint32_t
uc_gcd_32(uint32_t a, uint32_t b);
uint64_t
uc_gcd_64(uint64_t a, uint64_t b);
uint32_t
uc_phi_32(uint32_t N);
uint64_t
uc_phi_64(uint64_t N);
static inline uint32_t
uc_nextpow2(uint32_t x)
{
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
return x;
}
#ifdef __cplusplus
}
#endif
#endif
+76
View File
@@ -0,0 +1,76 @@
/*Copyright (c) 2004 Nils O. Selåsdal <NOS {on} Utel {dot} no> */
/*Straight forward attempt at a Mersenne Twister PRNG */
#include "ucore_mersenne_twister.h"
/*Beware , pollution. But the names are from the spec */
enum {
N = MT_RAND_N,
w = 32,
M = 387,
R = 19,
U = 0x80000000,
LL= 0x7FFFFFFF,
a = 0x9908B0DF,
s = 7,
t = 15,
b = 0x9D2C5680,
c = 0xEFC60000,
l = 18,
u = 11,
};
void mtsrand(int seed, MTRand *r)
{
int j;
for(j = 0 ; j < N ; j++) {
r->x[j] = seed * ((j+1)<< 3)|0x1;
}
r->i = 0;
}
unsigned int mtrand(MTRand *r)
{
unsigned int y;
unsigned int ch[] = {0, a};
y = r->x[r->i] & U;
y |= r->x[r->i % N];
y &= LL;
r->x[r->i] = r->x[(r->i + M ) %N];
r->x[r->i] ^= y >> 1;
r->x[r->i] ^= ch[y&0x1];
y = r->x[r->i];
y ^= y >> u;
y ^= (y << s) & b;
y ^= (y << t) & c;
y ^= y >> l;
r->i = (r->i + 1) % N;
return y;
}
#ifdef TEST_MT
#include <stdio.h>
#include <time.h>
int main(int argc,char *argv[])
{
MTRand r;
mtsrand(time(NULL),&r);
for(;;){
unsigned int _y = mtrand(&r);
if(_y < 100)
printf("%u \n",_y);
}
return 0;
}
#endif
+27
View File
@@ -0,0 +1,27 @@
#ifndef UCORE_MERSENNE_TWISTER_H
#define UCORE_MERSENNE_TWISTER_H
/** Context used for the PRNG*/
#define MT_RAND_N 624
typedef struct {
unsigned int x[MT_RAND_N];
int i;
} MTRand;
/** Initialize a Mersenne Twister PRNG context.
* @seed Starter seed for the PRNG
* @r context for the PRNG
*/
void mtsrand(int seed, MTRand *r);
/** Generate a new random number.
* Generated range is 0 to UINT_MAX
*
* @r context for the PRNG
* @return A pseudo random number
*/
unsigned int mtrand(MTRand *r);
#endif
+55
View File
@@ -0,0 +1,55 @@
#include "ucore_hash.h"
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
#define m 0x5bd1e995
#define r 24
uint32_t
uc_murmurmash2(const void *key, int len, uint32_t seed )
{
// Initialize the hash to a 'random' value
uint32_t h = seed ^ len;
// Mix 4 bytes at a time into the hash
const unsigned char * data = (const unsigned char *)key;
while(len >= 4)
{
uint32_t k = *(uint32_t *)data;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
data += 4;
len -= 4;
}
// Handle the last few bytes of the input array
switch(len)
{
case 3: h ^= data[2] << 16;
case 2: h ^= data[1] << 8;
case 1: h ^= data[0];
h *= m;
};
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
+257
View File
@@ -0,0 +1,257 @@
#ifndef UCORE_PACK_H_
#define UCORE_PACK_H_
#include <stdint.h>
#ifdef __GNUC__
# define UC_INLINE inline __attribute__((always_inline))
#else
# define UC_INLINE inline
#endif
/** Functions for serializing/de-serializing integers to and from
* byte arrays.
* These functions are independant of the host endian. Only
* thing to care about is the endian format of the data in
* the byte array.
*/
/** Serialize a uint16_t to a byte array in little endian format.
* @v The value to serialize
* @r The byte array to place the integer in. Must be at least of size 2.
*/
static UC_INLINE void uc_pack_16_le(uint16_t v, uint8_t *r)
{
r[0] = v;
r[1] = v >> 8;
}
/** De-serialize a uint16_t from a byte array in little endian format.
* @r The byte array to containing the integer in. Must be at least of size 2.
* @return The deserialized integer from the byte array.
*/
static UC_INLINE uint16_t uc_unpack_16_le(const uint8_t *r)
{
uint32_t v;
v = r[0];
v |= r[1] << 8;
return v;
}
/** Serialize a uint32_t to a 3 byte(24 bits) array in little endian format.
* Only the bottom 24 bits of the uint32_t are used.
*
* @v The value to serialize
* @r The byte array to place the integer in. Must be at least of size 3.
*/
static UC_INLINE void uc_pack_24_le(uint32_t v, uint8_t *r)
{
r[0] = v;
r[1] = v >> 8;
r[2] = v >> 16;
}
/** De-serialize a uint32_t from a 3 byte (24 bit) byte array in little endian format.
* @r The byte array to containing the integer in. Must be at least of size 3.
* @return The deserialized integer from the byte array.
*/
static UC_INLINE uint32_t uc_unpack_24_le(const uint8_t *r)
{
uint32_t v;
v = r[0];
v |= r[1] << 8;
v |= r[2] << 16;
return v;
}
/** Serialize a uint32_t to a byte array in little endian format.
* @v The value to serialize
* @r The byte array to place the integer in. Must be at least of size 4.
*/
static UC_INLINE void uc_pack_32_le(uint32_t v, uint8_t *r)
{
r[0] = v;
r[1] = v >> 8;
r[2] = v >> 16;
r[3] = v >> 24;
}
/** De-serialize a uint32_t from a byte array in little endian format.
* @r The byte array to containing the integer in. Must be at least of size 4.
* @return The deserialized integer from the byte array.
*/
static UC_INLINE uint32_t uc_unpack_32_le(const uint8_t *r)
{
uint32_t v;
v = r[0];
v |= r[1] << 8;
v |= r[2] << 16;
v |= r[3] << 24;
return v;
}
/** Serialize a uint64_t to a byte array in little endian format.
* @v The value to serialize
* @r The byte array to place the integer in. Must be at least of size 8
*/
static UC_INLINE void uc_pack_64_le(uint64_t v, uint8_t *r)
{
r[0] = v;
r[1] = v >> 8;
r[2] = v >> 16;
r[3] = v >> 24;
r[4] = v >> 32ULL;
r[5] = v >> 40ULL;
r[6] = v >> 48ULL;
r[7] = v >> 56ULL;
}
/** De-serialize a uint64_t from a byte array in little endian format.
* @r The byte array to containing the integer in. Must be at least of size 8.
* @return The deserialized integer from the byte array
*/
static UC_INLINE uint64_t uc_unpack_64_le(const uint8_t *r)
{
uint64_t v;
v = r[0];
v |= r[1] << 8;
v |= r[2] << 16;
v |= (uint32_t)r[3] << 24;
v |= (uint64_t)r[4] << 32ULL;
v |= (uint64_t)r[5] << 40ULL;
v |= (uint64_t)r[6] << 48ULL;
v |= (uint64_t)r[7] << 56ULL;
return v;
}
/** Serialize a uint16_t to a byte array in big endian format.
* @v The value to serialize
* @r The byte array to place the integer in. Must be at least of size 2.
*/
static UC_INLINE void uc_pack_16_be(uint32_t v, uint8_t *r)
{
r[0] = v >> 8;
r[1] = v;
}
/** De-serialize a uint16_t from a byte array in big endian format.
* @r The byte array to containing the integer in. Must be at least of size 2.
* @return The deserialized integer from the byte array
*/
static UC_INLINE uint16_t uc_unpack_16_be(const uint8_t *r)
{
uint16_t v;
v = r[0] << 8;
v |= r[1];
return v;
}
/** Serialize a uint32_t to a 3 byte(24 bits) array in big endian format.
* Only the bottom 24 bits of the uint32_t are used.
*
* @v The value to serialize
* @r The byte array to place the integer in. Must be at least of size 3.
*/
static UC_INLINE void uc_pack_24_be(uint32_t v, uint8_t *r)
{
r[0] = v >> 16;
r[1] = v >> 8;
r[2] = v;
}
/** De-serialize a uint32_t from a 3 byte (24 bit) byte array in big endian format.
* @r The byte array to containing the integer in. Must be at least of size 3.
* @return The deserialized integer from the byte array.
*/
static UC_INLINE uint32_t uc_unpack_24_be(const uint8_t *r)
{
uint32_t v;
v = r[0] << 16;
v |= r[1] << 8;
v |= r[2];
return v;
}
/** Serialize a uint32_t to a byte array in big endian format.
* @v The value to serialize
* @r The byte array to place the integer in. Must be at least of size 4.
*/
static UC_INLINE void uc_pack_32_be(uint32_t v, uint8_t *r)
{
r[0] = v >> 24;
r[1] = v >> 16;
r[2] = v >> 8;
r[3] = v;
}
/** De-serialize a uint32_t from a byte array in big endian format.
* @r The byte array to containing the integer in. Must be at least of size 4.
* @return The deserialized integer from the byte array
*/
static UC_INLINE uint32_t uc_unpack_32_be(const uint8_t *r)
{
uint32_t v;
v = r[0] << 24;
v |= r[1] << 16;
v |= r[2] << 8;
v |= r[3];
return v;
}
/** Serialize a uint16_t to a byte array in big endian format.
* @v The value to serialize
* @r The byte array to place the integer in. Must be at least of size 8
*/
static UC_INLINE void uc_pack_64_be(uint64_t v, uint8_t *r)
{
r[0] = v >> 56ULL;
r[1] = v >> 48ULL;
r[2] = v >> 40ULL;
r[3] = v >> 32ULL;
r[4] = v >> 24;
r[5] = v >> 16;
r[6] = v >> 8;
r[7] = v;
}
/** De-serialize a uint64_t from a byte array in big endian format.
* @r The byte array to containing the integer in. Must be at least of size 4.
* @return The deserialized integer from the byte array
*/
static UC_INLINE uint64_t uc_unpack_64_be(const uint8_t *r)
{
uint64_t v;
v = (uint64_t)r[0] << 56ULL;
v |= (uint64_t)r[1] << 48ULL;
v |= (uint64_t)r[2] << 40ULL;
v |= (uint64_t)r[3] << 32ULL;
v |= (uint32_t)r[4] << 24;
v |= r[5] << 16;
v |= r[6] << 8;
v |= r[7];
return v;
}
#undef UC_INLINE
#endif
+20
View File
@@ -0,0 +1,20 @@
#include "ucore_math.h"
/*
Euler's Totient Function is denoted by the Greek letter phi, and is defined as follows:
phi(N) = how many numbers between 1 and N - 1 which are relatively prime to N.
*/
uint32_t
uc_phi_32(uint32_t N)
{
uint32_t phi = 1;
uint32_t i;
for (i = 2 ; i < N ; ++i){
if (uc_gcd_32(i, N) == 1){
++phi;
}
}
return phi;
}
+20
View File
@@ -0,0 +1,20 @@
#include "ucore_math.h"
/*
Euler's Totient Function is denoted by the Greek letter phi, and is defined as follows:
phi(N) = how many numbers between 1 and N - 1 which are relatively prime to N.
*/
uint64_t
uc_phi_64(uint64_t N)
{
uint64_t phi = 1;
uint64_t i;
for (i = 2 ; i < N ; ++i){
if (uc_gcd_64(i, N) == 1){
++phi;
}
}
return phi;
}
+19
View File
@@ -0,0 +1,19 @@
#include "ucore_hash.h"
uint32_t
uc_pjwhash(const char *str,size_t len)
{
unsigned h = 0, g;
while (len--) {
h = (h << 4) + *str++;
if ((g = h & 0xf0000000)) {
h ^= (g >> 24);
h ^= g;
}
}
return h;
}
+336
View File
@@ -0,0 +1,336 @@
#include <stddef.h>
#include "ucore_rbtree.h"
//modified from generated code of tree.h
static void
rotateleft(RBTree *root, RBNode *node)
{
RBNode *right = node->right;
node->right = right->left;
if (right->left)
right->left->parent = node;
right->left = node;
right->parent = node->parent;
if (node->parent) {
if (node == node->parent->left)
node->parent->left = right;
else
node->parent->right = right;
} else
root->node = right;
node->parent = right;
}
static void
rotateright(RBTree *root, RBNode *node)
{
RBNode *left = node->left;
node->left = left->right;
if (left->right)
left->right->parent = node;
left->right = node;
left->parent = node->parent;
if (node->parent) {
if (node == node->parent->right)
node->parent->right = left;
else
node->parent->left = left;
} else
root->node = left;
node->parent = left;
}
static void
rb_insertcolor(RBTree *root, RBNode *node)
{
RBNode *parent, *gparent;
while ((parent = node->parent) && parent->color == Red) {
gparent = parent->parent;
if (parent == gparent->left) {
RBNode *uncle = gparent->right;
if (uncle && uncle->color == Red) {
uncle->color = Black;
parent->color = Black;
gparent->color = Red;
node = gparent;
continue;
}
if (parent->right == node) {
RBNode *tmp;
rotateleft(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
parent->color = Black;
gparent->color = Red;
rotateright(root, gparent);
}
else {
RBNode *uncle = gparent->left;
if (uncle && uncle->color == Red) {
uncle->color = Black;
parent->color = Black;
gparent->color = Red;
node = gparent;
continue;
}
if (parent->left == node) {
RBNode *tmp;
rotateright(root, parent);
tmp = parent;
parent = node;
node = tmp;
}
parent->color = Black;
gparent->color = Red;
rotateleft(root, gparent);
}
}
root->node->color = Black;
}
static void
removecolor(RBTree *root, RBNode *node, RBNode *parent)
{
RBNode *other;
while ((!node || node->color == Black) && node != root->node) {
if (parent->left == node) {
other = parent->right;
if (other->color == Red) {
other->color = Black;
parent->color = Red;
rotateleft(root, parent);
other = parent->right;
}
if ((!other->left || other->left->color == Black)
&& (!other->right
|| other->right->color == Black)) {
other->color = Red;
node = parent;
parent = node->parent;
} else {
if (!other->right
|| other->right->color == Black) {
RBNode *o_left;
if ((o_left = other->left))
o_left->color = Black;
other->color = Red;
rotateright(root, other);
other = parent->right;
}
other->color = parent->color;
parent->color = Black;
if (other->right)
other->right->color = Black;
rotateleft(root, parent);
node = root->node;
break;
}
}
else {
other = parent->left;
if (other->color == Red) {
other->color = Black;
parent->color = Red;
rotateright(root, parent);
other = parent->left;
}
if ((!other->left || other->left->color == Black)
&& (!other->right
|| other->right->color == Black)) {
other->color = Red;
node = parent;
parent = node->parent;
} else {
if (!other->left
|| other->left->color == Black) {
RBNode *o_right;
if ((o_right = other->right))
o_right->color = Black;
other->color = Red;
rotateleft(root, other);
other = parent->left;
}
other->color = parent->color;
parent->color = Black;
if (other->left)
other->left->color = Black;
rotateright(root, parent);
node = root->node;
break;
}
}
}
if (node)
node->color = Black;
}
void
uc_rb_remove(RBTree *root, RBNode *node)
{
RBNode *child, *parent;
int color;
if (!node->left)
child = node->right;
else if (!node->right)
child = node->left;
else {
RBNode *old = node, *left;
node = node->right;
while ((left = node->left))
node = left;
child = node->right;
parent = node->parent;
color = node->color;
if (child)
child->parent = parent;
if (parent) {
if (parent->left == node)
parent->left = child;
else
parent->right = child;
} else
root->node = child;
if (node->parent == old)
parent = node;
node->parent = old->parent;
node->color = old->color;
node->right = old->right;
node->left = old->left;
if (old->parent) {
if (old->parent->left == old)
old->parent->left = node;
else
old->parent->right = node;
} else
root->node = node;
old->left->parent = node;
if (old->right)
old->right->parent = node;
goto finish;
}
parent = node->parent;
color = node->color;
if (child)
child->parent = parent;
if (parent) {
if (parent->left == node)
parent->left = child;
else
parent->right = child;
} else
root->node = child;
finish:
if (color == Black)
removecolor(root, child, parent);
}
RBNode*
uc_rb_find(RBTree *root, const void *val)
{
RBNode *n = root->node;
while (n) {
int d = root->compare(val,n->data);
if (d < 0)
n = n->left;
else if (d > 0)
n = n->right;
else
return n;
}
return NULL;
}
RBNode*
uc_rb_insert(RBTree *root, RBNode *child)
{
RBNode **p = &root->node;
RBNode *parent = NULL;
int d;
while (*p) {
parent = *p;
d = root->compare(child->data, parent->data);
if (d < 0)
p = &(*p)->left;
else if (d > 0)
p = &(*p)->right;
else
return parent;
}
child->parent = parent;
child->color = Red;
child->left = child->right = NULL;
*p = child;
rb_insertcolor(root, child);
return NULL;
}
RBNode *uc_rb_first(const RBTree *root)
{
RBNode *n = root->node;
if(n == NULL)
return NULL;
while(n->left)
n = n->left;
return n;
}
RBNode *uc_rb_next(RBNode *node)
{
if(node->right) { //down and left of the right branch
node = node->right;
while(node->left)
node = node->left;
} else { //up until we are not the right node
while(node->parent && node == node->parent->right)
node = node->parent;
node = node->parent;
}
return node;
}
RBNode *uc_rb_last(const RBTree *root)
{
RBNode *n = root->node;
if(n == NULL)
return NULL;
while(n->right)
n = n->right;
return n;
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef RBTREE_H_
#define RBTREE_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef enum RBColor RBColor;
enum RBColor {
Red,
Black
};
typedef struct RBNode RBNode;
struct RBNode {
unsigned char color; //Red/Black
RBNode *parent;
RBNode *right;
RBNode *left;
void *data;
};
typedef struct RBTree RBTree;
struct RBTree {
RBNode *node;
int (*compare)(const void *a, const void *b);
};
void uc_rb_remove(RBTree *root, RBNode *node);
RBNode *uc_rb_find(RBTree *root, const void *val);
RBNode *uc_rb_insert(RBTree *root, RBNode *child);
RBNode *uc_rb_first(const RBTree *root);
RBNode *uc_rb_next(RBNode *node);
RBNode *uc_rb_last(const RBTree *root);
#ifdef __cplusplus
}
#endif
#endif
+82
View File
@@ -0,0 +1,82 @@
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "ucore_read_file.h"
#define CHUNK_SZ 1024
char *
uc_read_file(const char *f, size_t *length, size_t max)
{
int fd;
char *s = NULL;
char *p;
struct stat statb;
size_t alloc_sz;
*length = 0;
if ((fd = open(f, O_RDONLY)) == -1)
return NULL;
if (fstat(fd, &statb) == -1) {
goto out_close;
}
if ((statb.st_mode & S_IFMT) == S_IFREG) {
if((size_t)statb.st_size > max) {
errno = EMSGSIZE;
goto out_close;
}
alloc_sz = (size_t) statb.st_size + 1; // + 1 to avoid one realloc
s = malloc((size_t) alloc_sz + 1); //+1 for nul terminator
} else {
alloc_sz = CHUNK_SZ;
s = malloc(alloc_sz + 1); //+1 for nul terminator
}
if (s == NULL) {
goto out_close;
}
p = s;
for(;;) {
ssize_t rc = read(fd, p, alloc_sz - (p - s));
if(rc == 0) {
*p = 0; // nul terminate. all malloc calls adds room for this byte
goto out_close;
} else if (rc == -1) {
goto out_err_free;
} else if(*length + rc > max) {
errno = EMSGSIZE;
goto out_err_free;
}
if(p + rc == s + alloc_sz) { //reached end of allocated memory, grow it.
char *tmp = realloc(s, alloc_sz + CHUNK_SZ + 1);
if(tmp == NULL) {
goto out_err_free;
}
s = tmp;
p = s + alloc_sz;
alloc_sz += CHUNK_SZ;
} else {
p += rc;
}
*length += rc;
}
out_err_free:
free(s);
s = NULL;
out_close:
close(fd);
return s;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef UCORE_READ_FILE_H_
#define UCORE_READ_FILE_H_y
#include <stddef.h>
/** Read the content of a file.
* The returned char* is malloced memory and must be freed by the caller.
* The content is terminated by a nul byte, regardless of whether the content
* is binary or text. The returned length does not include this nul byte.
*
* @file_name name of the file
* @length Returned length of the content read
* @max Fail if the read content length is greater than max.
* @return The content read from the file, or NULL if something failed
* (inspect errno to see why it failed)
*/
char *
uc_read_file(const char *file_name, size_t *length, size_t max);
#endif
+146
View File
@@ -0,0 +1,146 @@
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include "ucore_salloc.h"
typedef struct Chunk Chunk;
struct Chunk {
Chunk *next;
size_t firstfree; //index to the first free byte in this chunk
union data { //for alignment
long long ll;
void *p;
double d;
size_t sz;
int i;
char data[1];
} data;
};
struct SAlloc {
size_t chunksz; //data size of each chunk
Chunk *first; //head of the chunk list
Chunk *current;
};
static Chunk *
add_chunk(SAlloc *p)
{
Chunk *newchunk;
newchunk = malloc(sizeof *newchunk + p->chunksz - (sizeof *newchunk - offsetof(Chunk, data.data)));
if(newchunk == NULL)
return NULL;
if(p->current != NULL)
p->current->next = newchunk;
newchunk->next = NULL;
newchunk->firstfree = 0;
return newchunk;
}
static Chunk *
next_chunk(SAlloc *p)
{
Chunk *newchunk;
if(p->current->next) {
newchunk = p->current->next;
newchunk->firstfree = 0;
} else
newchunk = add_chunk(p);
if(newchunk)
p->current = newchunk;
return newchunk;
}
SAlloc *
uc_new_salloc(size_t chunksz)
{
SAlloc *p;
Chunk *first;
p = malloc(sizeof *p);
if(p == NULL)
return NULL;
p->chunksz = chunksz;
p->current = NULL;
if((first = add_chunk(p)) == NULL) {
free(p);
return NULL;
}
p->first = p->current = first;
return p;
}
void
uc_reset_salloc(SAlloc *p)
{
Chunk *tmp;
for(tmp = p->first; tmp; tmp = tmp->next)
tmp->firstfree = 0;
p->current = p->first;
}
void *
uc_s_alloc(SAlloc *p,size_t sz)
{
Chunk *chunk;
void *newmem;
chunk = p->current;
if(chunk->firstfree + sz > p->chunksz) {
if(sz > p->chunksz)
return NULL;
chunk = next_chunk(p);
if(chunk == NULL)
return NULL;
}
newmem = &chunk->data.data[chunk->firstfree];
chunk->firstfree += sz;
return newmem;
}
void *
uc_s_allocz(SAlloc *p,size_t sz)
{
void *newmem = uc_s_alloc(p, sz);
if(newmem != NULL)
memset(newmem, 0, sz);
return newmem;
}
static void
free_chunks(Chunk *chunk)
{
Chunk *next;
for(next = NULL; chunk != NULL; chunk = next) {
next = chunk->next;
free(chunk);
}
}
void
uc_free_salloc(SAlloc *p)
{
free_chunks(p->first);
free(p);
}
+70
View File
@@ -0,0 +1,70 @@
#ifndef SALLOC_H_
#define SALLOC_H_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Sequntial memory allocator
*
* Allocates bigger chunks of memory at a time, to save the amount of malloc call,
* and enables you to free all that memory in one sweep.
*
* This means that once allocated, a piece of memory obtained from the
* allocator cannot be free'd individually, only the entire SAlloc can be free'd.
*
* Memory is allocated using the underlying malloc() in chunk sizes.
* Once a particular SAlloc has given out all memory in a chunk, a new chunk
* is allocated again, using the underlying malloc().
*
*/
/** Opaque handle to a SAlloc */
typedef struct SAlloc SAlloc;
/** Create a new SAlloc with the given size for each chunk.
* e.g. uc_new_salloc(sizeof(struct Foo) * 1000); will immedeatly
* allocate memory to hold 1000 struct Foo's. Once all that memory is
* handed out from this SAlloc, another piece of memory is allocaterd
* for another 1000 struct Foo's.. All these memory pieces are released
* when the uc_free_salloc() is called.
*
* @chunksz Size of each piece of memory block allocated.
* @return A new handle for a SAlloc, or NULL.
*/
SAlloc *uc_new_salloc(size_t chunksz);
/** Allocate memory from a SAlloc.
* @sz size of the memory. This must be <= the chunksz the SAlloc was
* created with.
* @return The new memory, or NULL if sz > chunksz or an underlying
* malloc call fails.
*/
void * uc_s_alloc(SAlloc *p,size_t sz);
/** Just like uc_s_alloc, but zero out the memory before returning it.
*/
void * uc_s_allocz(SAlloc *p,size_t sz);
/** Free the SAlloc and all memory associated with this SAlloc.
* The SAlloc is not usable any more after this call.
*
* @p The SAlloc to free.
*/
void uc_free_salloc(SAlloc *p);
/** Reset this SAlloc, effectivly releasing all the memory obtained.
* The SAlloc is still usable after this call.
* The actual memory previously allocated from this SAlloc is cached,
* and will be reused by subsequent uc_s_alloc calls.
*
* @p The SAlloc to reset.
*/
void uc_reset_salloc(SAlloc *p);
#ifdef __cplusplus
}
#endif
#endif
+15
View File
@@ -0,0 +1,15 @@
#include "ucore_hash.h"
uint32_t
sax_hash(void *key, size_t len)
{
unsigned char *p = key;
unsigned h = 0;
size_t i;
for ( i = 0; i < len; i++ )
h ^= ( h << 5 ) + ( h >> 2 ) + p[i];
return h;
}
+12
View File
@@ -0,0 +1,12 @@
unsigned long
sdbmhash(const unsigned char *str)
{
unsigned long hash = 0;
unsigned int c;
while ((c = *str++))
hash = c + (hash << 6) + (hash << 16) - hash;
return hash;
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef SEQ_H_
#define SEQ_H_
#include <stdint.h>
// Check if a is before b, taking care of wrap arounds
static inline int seq_before(uint32_t a, uint32_t b)
{
return (int32_t)(a - b) < 0;
}
// check if a is before b, taking care of wrap arounds
#define seq_after(a, b) before(b, a)
//check if a is between b or c
static inline int seqbetween(uint32_t a, uint32_t b, uint32_t c)
{
return c - b >= a - b;
}
#endif
+21
View File
@@ -0,0 +1,21 @@
#include <stdint.h>
#include <stddef.h>
#include "ucore_string.h"
char*
uc_sprintb(char *result, unsigned int value)
{
char *s = result;
unsigned mask = ~((unsigned) (~0) >> 1);
if (s) {
while (mask) {
*s++ = (mask & value) ? '1' : '0';
mask >>= 1;
}
*s = '\0';
}
return result;
}
+21
View File
@@ -0,0 +1,21 @@
#include <stdint.h>
#include <stddef.h>
#include "ucore_string.h"
char*
uc_sprintbc(char *result, unsigned char value)
{
char *s = result;
unsigned char mask = ~((unsigned char) (~0) >> 1);
if (s) {
while (mask) {
*s++ = (mask & value) ? '1' : '0';
mask >>= 1;
}
*s = '\0';
}
return result;
}
+20
View File
@@ -0,0 +1,20 @@
#include <stdint.h>
#include <stddef.h>
#include "ucore_string.h"
char*
uc_sprintbll(char *result, unsigned long long value)
{
char *s = result;
unsigned long long mask = ~((unsigned long long) (~0) >> 1);
if (s) {
while (mask) {
*s++ = (mask & value) ? '1' : '0';
mask >>= 1;
}
*s = '\0';
}
return result;
}
+20
View File
@@ -0,0 +1,20 @@
#include <stdint.h>
#include <stddef.h>
#include "ucore_string.h"
char*
uc_sprintbs(char *result, unsigned short value)
{
char *s = result;
unsigned short mask = ~((unsigned short) (~0) >> 1);
if (s) {
while (mask) {
*s++ = (mask & value) ? '1' : '0';
mask >>= 1;
}
*s = '\0';
}
return result;
}
+60
View File
@@ -0,0 +1,60 @@
#ifndef UCORE_STRING_H_
#define UCORE_STRING_H_
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
size_t
uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result);
size_t
uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result);
char*
uc_hex_encode(const uint8_t *in, size_t len, char *out);
uint8_t*
uc_hex_decode(const char *in, size_t maxlen,uint8_t *out);
char*
uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, char *delim);
void
uc_str_tolower(char *s);
void
uc_str_toupper(char *s);
#define UC_BCD_LEN(ascii_len) ((ascii_len) / 2 + ((ascii_len) % 2))
#define UC_ASCII_LEN(bcd_len) ((bcd_len) * 2 + 1)
size_t
uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler);
size_t
uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout);
char*
uc_sprintb(char *result, unsigned int value);
char*
uc_sprintbc(char *result, unsigned char value);
char*
uc_sprintbll(char *result, unsigned long long value);
char*
uc_sprintbs(char *result, unsigned short value);
int
getfields(char *str, char **args, int max, int mflag, const char *set);
//ocnvert bytes to a human representable test, (i.e. 12kB, 160 MB 1.78 GB etc.
///result should be at least of size 12,
///returns the result argument
char *
uc_human_bytesz(uint64_t bytes, char *result, size_t result_len);
#ifdef __cplusplus
}
#endif
#endif
+12
View File
@@ -0,0 +1,12 @@
#include <ctype.h>
#include "ucore_string.h"
void
uc_str_tolower(char *s)
{
while (*s) {
*s = tolower((unsigned char)*s);
s++;
}
}
+12
View File
@@ -0,0 +1,12 @@
#include <ctype.h>
#include "ucore_string.h"
void
uc_str_toupper(char *s)
{
while (*s) {
*s = toupper((unsigned char)*s);
s++;
}
}
+157
View File
@@ -0,0 +1,157 @@
#include <assert.h>
#include "ucore_timers.h"
static int timers_cmp(const void *a_, const void *b_)
{
const struct UCTimer *a = a_;
const struct UCTimer *b = b_;
if(timercmp(&a->timeout, &b->timeout, <)) {
return -1;
} else if (timercmp(&a->timeout, &b->timeout, >)) {
return 1;
} else { //check sequence number
if(a->seq < b->seq) {
return -1;
} else if(a->seq > b->seq) {
return 1;
} else { //should never happen
//assert(0);
return 0;
}
}
//assert(0);
return 0; //silence compiler
}
static void uc_timer_real_add(struct UCTimers *timers, struct UCTimer *timer)
{
uc_timer_remove(timers, timer); //re schedule it if it's already running
timer->state = UC_TIMER_ACTIVE;
timer->seq = timers->seq++;
timer->rb_node.data = timer; //point the data in a RBNode back to the timer that contains it.
uc_rb_insert(&timers->timers, &timer->rb_node);
}
void uc_timers_init(struct UCTimers *t)
{
t->timers.node = NULL;
t->timers.compare = timers_cmp;
t->seq = 0;
TAILQ_INIT(&t->ready_list);
}
void uc_timer_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int usec)
{
struct timeval now;
struct timeval tmp;
assert(timer->callback != NULL);
if(timer->callback == NULL) //must be set.
return;
tmp.tv_sec = sec;
tmp.tv_usec = usec;
gettimeofday(&now, NULL);
timeradd(&now, &tmp, &timer->timeout);
uc_timer_real_add(timers, timer);
}
void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer)
{
if(timer->state == UC_TIMER_INACTIVE) { //already removed , or never added.
//debugging bandaid
timer->ready_entry.tqe_next = (struct UCTimer *)104;
timer->ready_entry.tqe_prev = (struct UCTimer **)105;
return;
}
uc_rb_remove(&timers->timers, &timer->rb_node); //remove it, safe for the
//callback to re_add it
if(timer->state == UC_TIMER_PENDING) {
//timer is pending for callback, remove it from the list
//so code in uc_timers_run does not touch it.
TAILQ_REMOVE(&timers->ready_list, timer, ready_entry);
}
timer->state = UC_TIMER_INACTIVE;
}
int uc_timers_first(const struct UCTimers *timers, struct timeval *first)
{
const RBNode *n = uc_rb_first(&timers->timers);
if(n) {
struct UCTimer *timer = n->data;
*first = timer->timeout;
return 0;
}
return 1;
}
size_t uc_timer_count(const struct UCTimers *timers)
{
struct RBNode *n;
size_t count = 0;
for(n = uc_rb_first(&timers->timers); n ; n = uc_rb_next(n)) {
count++;
}
return count;
}
int uc_timer_running(const struct UCTimer *timer)
{
return timer->state;
}
int uc_timers_run(struct UCTimers *timers, const struct timeval *now)
{
RBNode *node;
int cnt = 0;
/* First find all the expired nodes, place them in a linked list.
* Callbacks cannot be performed here, as the callback might alter
* the rbtree and timers
*/
assert(TAILQ_EMPTY(&timers->ready_list)); //somethings serious wrong if it isn't already empty
TAILQ_INIT(&timers->ready_list);
for(node = uc_rb_first(&timers->timers); node ; node = uc_rb_next(node)) {
struct UCTimer *t = node->data;
//Note, timercmp does not work for >=
if(!timercmp(now, &t->timeout, <)) {
TAILQ_INSERT_TAIL(&timers->ready_list, t, ready_entry);
t->state = UC_TIMER_PENDING; //so uc_timer_remove knows
//it have to remove it from the ready_list
} else {
break;
}
}
/*run through the list and fire callbacks.
* It is ok for a callback to remove another
* timer that's either running or pending
* Need to always pick the first item in the tail queue
* since a timer callback could remove/free a timer
* we had in the list.
* uc_timer_remove will unlink the timer from this list.
*/
while(!TAILQ_EMPTY(&timers->ready_list)) {
struct UCTimer *t = TAILQ_FIRST(&timers->ready_list);
uc_timer_remove(timers, t);
assert(t->callback != NULL);
t->callback(timers, t); //fire
// callback might have free'd its timer.
// Do not touch 't' after this.
cnt++;
}
return cnt;
}
+63
View File
@@ -0,0 +1,63 @@
#ifndef UCORE_TIMERS_H_
#define UCORE_TIMERS_H_
#include <stddef.h>
#include <sys/queue.h>
#include <sys/time.h>
#include "ucore_rbtree.h"
struct UCTimer;
struct UCTimers;
//timer states
enum {
//not running
UC_TIMER_INACTIVE = 0,
//running
UC_TIMER_ACTIVE = 1,
//running and pending to be fired in this run of uc_timers_run
UC_TIMER_PENDING = 2
};
typedef void (*uc_timer_cb)(struct UCTimers *timers, struct UCTimer *timer);
struct UCTimer {
//internal members
RBNode rb_node; //the RBNode will hold a data pointer to the
//the UCTimer it's a member of. We might get rid of that member, and use CONTAINER_OF
//to find the UCTimer from a RBNode
//
//absolute time when the timer should be fired
struct timeval timeout;
size_t seq; //needed to keep timeout unique
//as the rbtree can only handle unique values
unsigned char state;
TAILQ_ENTRY(UCTimer) ready_entry; //entry in ready_list in UCTimers
//callback function
uc_timer_cb callback;
//user data for the callback
void *cookie_ptr;
int cookie_int;
int cookie_int2;
};
struct UCTimers {
RBTree timers;
size_t seq; //used to generate unique timers
TAILQ_HEAD(, UCTimer) ready_list; //pending timers to be fired while inside uc_timers_run
};
void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer);
void uc_timers_init(struct UCTimers *t);
void uc_timer_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int usec);
void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer);
int uc_timers_first(const struct UCTimers *timers, struct timeval *first);
size_t uc_timer_count(const struct UCTimers *timers);
int uc_timer_running(const struct UCTimer *timer);
int uc_timers_run(struct UCTimers *timers, const struct timeval *now);
#endif
+51
View File
@@ -0,0 +1,51 @@
#include <sys/time.h>
struct timeval *
uc_tvadd(struct timeval *dst, const struct timeval *a, const struct timeval *b)
{
dst->tv_sec = a->tv_sec + b->tv_sec;
dst->tv_usec = a->tv_usec + b->tv_usec;
if (dst->tv_usec >= 1000000)
dst->tv_sec++, dst->tv_usec -= 1000000;
return dst;
}
struct timeval *
uc_tvsub(struct timeval *dst, const struct timeval *a, const struct timeval *b)
{
dst->tv_sec = a->tv_sec - b->tv_sec;
dst->tv_usec = a->tv_usec - b->tv_usec;
if (dst->tv_usec < 0)
dst->tv_sec--, dst->tv_usec += 1000000;
return dst;
}
int
uc_tvcmp(const struct timeval *a, const struct timeval *b)
{
if(a->tv_sec < b->tv_sec)
return -1;
else if(a->tv_sec > b->tv_sec)
return 1;
if (a->tv_usec < b->tv_usec)
return -1;
else if (a->tv_usec > b->tv_usec)
return 1;
return 0;
}
struct timeval *
uc_to2tv(struct timeval *dst, unsigned long ms)
{
dst->tv_sec = ms / 1000;
dst->tv_usec = ms % 1000 * 1000;
return dst;
}
+54
View File
@@ -0,0 +1,54 @@
#ifndef UCORE_UTILS_H_
#define UCORE_UTILS_H_
#include <stddef.h>
//Gnerate a compiler error if the compile time
//constant expression fails
#define STATIC_ASSERT(expr) \
do { \
enum { assert_static__ = 1/(expr) }; \
} while (0)
#ifdef DEBUG
#define TRACEF(fmt, ...)\
do { \
fprintf(stderr, "%s:%s(%d)" fmt, __FILE__, __FUNCTION__, __LINE,__VA_ARGS__);\
} while(0)
#else
#define TRACEF(fmt, ...)
#endif
//MAX of a and b
#define UC_MAX(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
//min of a and b
#define UC_MIN(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
//given 'ptr' as a pointer to a struct 'member',
//find the struct that ptr is the member of, where
//'type' is the type of the containing struct
//e.g.
//struct foo {
// int i;
// struct bar zap;
//};
// ...
//struct bar *p = ..; //the local p is a pointer to
//a 'zap' member inside a struct foo.
//give us the struct foo*:
//struct foo *f = CONTAINER_OF(p, struct foo, zap);
#define CONTAINER_OF(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type, member) ); })
#endif
+7
View File
@@ -0,0 +1,7 @@
const int ucore_version_major = @version_major@;
const int ucore_version_minor = @version_minor@;
const int ucore_version_patch = @version_patch@;
const char ucore_version_str[] = "@version_major@.@version_minor@.@version_patch@.@version_revision@";
+11
View File
@@ -0,0 +1,11 @@
#ifndef UCORE_VERSION_H_
#define UCORE_VERSION_H_
extern const int ucore_version_major;
extern const int ucore_version_minor;
extern const int ucore_version_patch;
extern const char ucore_version_str[];
#endif
+22
View File
@@ -0,0 +1,22 @@
import os
Import('env', 'build_type', 'prefix', 'version_info', 'test_xml')
test_env = env.Clone()
test_env.Append(LIBPATH = ['#build/src']);
test_env.Append(CPPPATH = ['#src'])
test_env.Append(LIBS = ['ucore_' + build_type, 'check'])
tests = test_env.Glob('test_*.c')
test_executable = 'test_runner'
#run test_runner --xml to produce an xml result file
if test_xml:
test_executable += ' --xml'
prog = test_env.Program('test_runner', tests)
cmd = test_env.Command(target='test_phony' ,
source = None,
action= test_env.Dir('.').abspath + '/' + test_executable)
test_env.Depends(cmd, prog)
test_env.AlwaysBuild(cmd)
+33
View File
@@ -0,0 +1,33 @@
#include <stdio.h>
#include <unistd.h>
#include "iomux.h"
extern struct IOMuxFD s_fd;
void stdin_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
{
char buf[64];
ssize_t len = read(fd->fd, buf, sizeof buf);
printf("Read %d bytes\n", len);
iomux_unregister_fd(mux, fd);
if(len > 0) {
s_fd.what = MUX_EV_READ;
iomux_register_fd(mux, &s_fd);
}
}
struct IOMuxFD s_fd = {
.fd = 0,
.what = MUX_EV_READ,
.callback = stdin_read_cb,
};
int main(int argc, char *argv[])
{
struct IOMux *mux = iomux_create(IOMUX_TYPE_DEFAULT);
iomux_register_fd(mux, &s_fd);
iomux_run(mux);
return 0;
}
+88
View File
@@ -0,0 +1,88 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "iomux.h"
extern struct IOMuxFD s_fd;
void stdin_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
{
char buf[4096];
ssize_t len = read(fd->fd, buf, sizeof buf);
if(len <= 0) {
perror("read");
fprintf(stderr,"Unregister stdin fd %d\n", fd->fd);
iomux_unregister_fd(mux, fd);
close(fd->fd);
close(fd->cookie_int);
}
else
write(fd->cookie_int, buf, len);
}
void pipe_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
{
char buf[4095];
ssize_t len = read(fd->fd, buf, sizeof buf);
if(len <= 0) {
perror("pipe read");
printf("Unregister pipe fd %d [stdout]\n", fd->fd);
fprintf(stderr,"Unregister pipe fd %d[stderr]\n", fd->fd);
iomux_unregister_fd(mux, fd);
close(fd->cookie_int);
fclose(fd->cookie_ptr);
} else {
fwrite(buf, 1 , len, fd->cookie_ptr);
fflush(fd->cookie_ptr);
}
}
void *writer(void *arg)
{
struct IOMux *mux = arg;
iomux_run(mux);
printf("writer mux returned\n");
return NULL;
}
int main(int argc, char *argv[])
{
struct IOMux *mux1 = iomux_create(IOMUX_TYPE_DEFAULT);
struct IOMux *mux2 = iomux_create(IOMUX_TYPE_DEFAULT);
int pfd[2];
int rc;
struct IOMuxFD fd1 = {0};
struct IOMuxFD fd2 = {0};
pthread_t tid;
pipe(pfd);
fd1.fd = 0;
fd1.what = MUX_EV_READ;
fd1.cookie_int = pfd[1];
fd1.callback = stdin_read_cb;
fd2.fd = pfd[0];
fd2.what = MUX_EV_READ;
fd2.cookie_ptr = fopen("out", "wb");
fd2.callback = pipe_read_cb;
rc = iomux_register_fd(mux1, &fd1);
if(rc != 0)
printf("Cannot register fd1: %s\n", strerror(rc));
rc = iomux_register_fd(mux2, &fd2);
if(rc != 0)
printf("Cannot register fdw: %s\n", strerror(rc));
pthread_create(&tid,NULL,writer,mux2);
iomux_run(mux1);
printf("reader mux returned\n");
pthread_join(tid, NULL);
iomux_delete(mux1);
iomux_delete(mux2);
return 0;
}
+140
View File
@@ -0,0 +1,140 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "iomux.h"
#define BUFLEN (4098*66)
struct Copy {
struct IOMuxFD in;
struct IOMuxFD out;
char buffer[BUFLEN];
size_t w_idx;
size_t r_idx;
int out_running;
};
void in_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
{
struct Copy *copy_ctx = fd->cookie_ptr;
size_t left = BUFLEN - copy_ctx->w_idx;
ssize_t rc;
left /= 2;
if(left == 0)
left++;
rc = read(fd->fd, &copy_ctx->buffer[copy_ctx->w_idx], left);
if(rc <= 0) {
if(rc == -1 && errno == EAGAIN) {
return;
} else if(rc == -1) {
perror("read");
}
iomux_unregister_fd(mux, fd);
return;
}
copy_ctx->w_idx += rc;
if(!copy_ctx->out_running) {
copy_ctx->out.what = MUX_EV_WRITE;
iomux_register_fd(mux, &copy_ctx->out);
copy_ctx->out_running = 1;
}
if(copy_ctx->w_idx == BUFLEN) {
iomux_unregister_fd(mux, fd);
}
}
void out_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event)
{
struct Copy *copy_ctx = fd->cookie_ptr;
ssize_t rc;
size_t len = copy_ctx->w_idx - copy_ctx->r_idx;
rc = write(1, &copy_ctx->buffer[copy_ctx->r_idx], len);
if(rc <= 0) {
if(rc == -1 && errno == EAGAIN) {
return;
} else {
perror("write");
iomux_unregister_fd(mux, &copy_ctx->in);
}
iomux_unregister_fd(mux, fd);
copy_ctx->out_running = 0;
} else {
copy_ctx->r_idx += rc;
if(copy_ctx->r_idx == copy_ctx->w_idx) {
iomux_unregister_fd(mux, fd);
copy_ctx->out_running = 0;
if(copy_ctx->w_idx == BUFLEN) {
copy_ctx->w_idx = 0;
copy_ctx->r_idx = 0;
iomux_register_fd(mux, &copy_ctx->in);
}
}
}
}
int set_nonblocking(int fd)
{
int flags = fcntl(fd,F_GETFL,NULL);
if(flags < 0 ) {
return flags;
}
return fcntl(fd,F_SETFL,flags | O_NONBLOCK);
}
void timer_cb(struct UCTimers *timers, struct UCTimer *timer)
{
fprintf(stderr, "Timer %d fired\n", timer->cookie_int);
struct UCTimer *t = calloc(1, sizeof *t);
t->callback = timer_cb;
t->cookie_int = timer->cookie_int + 1;
uc_timer_add(timers, t, 5,5);
t = calloc(1, sizeof *t);
t->callback = timer_cb;
t->cookie_int = timer->cookie_int + 2;
uc_timer_add(timers, t, 5,4);
}
int main(int argc, char *argv[])
{
struct Copy copy_ctx = {
.in = {
.fd = 0,
.what = MUX_EV_READ,
.callback = in_cb,
.cookie_ptr = &copy_ctx,
},
.out = {
.fd = 1,
.callback = out_cb,
.cookie_ptr = &copy_ctx,
}
};
struct UCTimer timer = {
.callback = timer_cb,
};
set_nonblocking(0);
set_nonblocking(1);
struct IOMux *mux = iomux_create(IOMUX_TYPE_EPOLL);
iomux_register_fd(mux, &copy_ctx.in);
uc_timer_add(iomux_get_timers(mux), &timer, 5, 0);
iomux_run(mux);
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
#include "ucore_logging.h"
#include "ucore_utils.h"
#include <syslog.h>
enum {
MAIN,
CC,
HO
};
struct uc_log_module module_arr[] = {
{
MAIN,
"MAIN",
"Main module",
UC_LL_WARNING
},
{
CC,
"CC",
"Call Control module",
UC_LL_DEBUG,
},
{
HO,
"HO",
"Handover module",
UC_LL_DEBUG
}
};
struct uc_log_modules modules = {
.mods = module_arr,
.cnt = ARRAY_SIZE(module_arr),
};
int main(int argc, char *argv[])
{
struct uc_log_destination *dest = uc_log_new_stderr(UC_LL_INFO, 0);
uc_log_init(&modules);
uc_log_add_destination(dest);
dest = uc_log_new_file("test.log", UC_LL_INFO, 1);
uc_log_add_destination(dest);
dest = uc_log_new_syslog("log.test", LOG_DAEMON, UC_LL_INFO, 0);
uc_log_add_destination(dest);
UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 2);
UC_LOGF( UC_LL_WARNING, HO, "Test HO warning%d\n", 2);
UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN info \n" );
UC_LOGF( UC_LL_WARNING, MAIN, "Test MAIN warning\n" );
uc_log_module_set_loglevel(MAIN, UC_LL_INFO);
UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN warning 2\n" );
return 1;
}
+27
View File
@@ -0,0 +1,27 @@
#include <string.h>
#include "ucore_salloc.h"
// Intended to be run under valgrind. Should show no errors
int main(int argc, char *argv)
{
size_t i;
SAlloc *s = uc_new_salloc(36 * 100);
for(i = 0; i < 100; i++) {
void *p = uc_s_alloc(s, 36);
memset(p,7,36);
}
uc_free_salloc(s);
s = uc_new_salloc(85 * 100);
for(i = 0; i < 100 * 3; i++) {
void *p = uc_s_alloc(s, 85);
memset(p,7,85);
}
uc_free_salloc(s);
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
#include <stdio.h>
#include "ucore_seq.h"
void check_before(uint32_t a, uint32_t b)
{
printf("%lu before %lu = %d\n", a ,b, seq_before(a, b));
}
int main(int argc, char *argv[])
{
check_before(0, 1);
check_before(1, 0);
check_before(0, 0xffffffff);
check_before(0, 0xffff);
check_before(0, 0x1ffff);
check_before(0xffff, 0xffffffff);
check_before(0x7fffffffU - 1, 0xffffffff);
check_before(0x7fffffffU + 1, 0xffffffff);
check_before(0x7fffffffU + 1, 0x7fffffffU);
check_before(0x7fffffffU - 1, 0x7fffffffU);
check_before(0x7fffffffU, 0x7fffffffU - 1);
check_before(0x7fffffffU, 0x7fffffffU + 1);
return 1;
}
+151
View File
@@ -0,0 +1,151 @@
#include <check.h>
#include "ucore_string.h"
START_TEST (test_2bcd_1234567890)
char ascii[] = "1234567890";
unsigned char bcd[5];
size_t len = uc_ascii2bcd(ascii, bcd, 0);
fail_if(len != 5, "len is %zu", len);
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
fail_if(bcd[1] != 0x43,"was 0x%x",bcd[1]);
fail_if(bcd[2] != 0x65,"was 0x%x",bcd[2]);
fail_if(bcd[3] != 0x87,"was 0x%x",bcd[3]);
fail_if(bcd[4] != 0x09,"was 0x%x",bcd[4]);
END_TEST
START_TEST (test_2bcd_empty)
char ascii[] = "";
unsigned char bcd[1];
size_t len = uc_ascii2bcd(ascii, bcd, 3);
fail_if(len != 0, "len is %zu", len);
END_TEST
START_TEST (test_2bcd_1_filler)
char ascii[] = "1";
unsigned char bcd[1];
size_t len = uc_ascii2bcd(ascii, bcd, 0xa);
fail_if(len != 1, "len is %zu", len);
fail_if(bcd[0] != 0xa1,"was 0x%x",bcd[0]);
END_TEST
START_TEST (test_2bcd_2_filler)
char ascii[] = "123";
unsigned char bcd[2];
size_t len = uc_ascii2bcd(ascii, bcd, 0xf);
fail_if(len != 2, "len is %zu", len);
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
fail_if(bcd[1] != 0xf3,"was 0x%x",bcd[1]);
END_TEST
START_TEST (test_2bcd_3_filler)
char ascii[] = "123";
unsigned char bcd[2];
size_t len = uc_ascii2bcd(ascii, bcd, 0x0);
fail_if(len != 2, "len is %zu", len);
fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]);
fail_if(bcd[1] != 0x03,"was 0x%x",bcd[1]);
END_TEST
START_TEST (test_2bcd_non_digits)
char ascii[] = "a,b{ }=";
unsigned char bcd[10];
size_t len = uc_ascii2bcd(ascii, bcd, 0x0);
fail_if(len != 0, "len is %zu", len);
END_TEST
START_TEST (test_2bcd_phoneno)
char ascii[] = "0047-3233-4";
unsigned char bcd[24];
size_t len = uc_ascii2bcd(ascii, bcd, 0xf);
fail_if(len != 5, "len is %zu", len);
fail_if(bcd[0] != 0x00,"was 0x%x",bcd[0]);
fail_if(bcd[1] != 0x74,"was 0x%x",bcd[1]);
fail_if(bcd[2] != 0x23,"was 0x%x",bcd[1]);
fail_if(bcd[3] != 0x33,"was 0x%x",bcd[1]);
fail_if(bcd[4] != 0xf4,"was 0x%x",bcd[1]);
END_TEST
START_TEST (test_2bcd_binary)
char ascii[] = {0x32,0x01,0xAF,0xFF,0x00};
unsigned char bcd[24];
size_t len = uc_ascii2bcd(ascii, bcd, 0xf);
fail_if(len != 1, "len is %zu", len);
fail_if(bcd[0] != 0xf2,"0 was 0x%x",bcd[0]);
END_TEST
START_TEST (test_2hex_1)
unsigned char bcd[] = {0x21, 0x43 };
char ascii[sizeof bcd * 2 + 1];
size_t len = uc_bcd2ascii(bcd, sizeof bcd, ascii);
fail_if(len != 4, "len is %zu", len);
fail_if(ascii[0] != '1',"0 was %c",ascii[0]);
fail_if(ascii[1] != '2',"1 was %c",ascii[1]);
fail_if(ascii[2] != '3',"2 was %c",ascii[2]);
fail_if(ascii[3] != '4',"3 was %c",ascii[3]);
fail_if(ascii[4] != 0, "4 was %c",ascii[4]);
END_TEST
START_TEST (test_2hex_2)
unsigned char bcd[] = {0xF0, 0xFF, 0x00};
char ascii[sizeof bcd * 2 + 1];
size_t len = uc_bcd2ascii(bcd, sizeof bcd, ascii);
fail_if(len != 6, "len is %zu", len);
fail_if(ascii[0] != '0',"0 was %c",ascii[0]);
fail_if(ascii[1] != 'F',"1 was %c",ascii[1]);
fail_if(ascii[2] != 'F',"2 was %c",ascii[2]);
fail_if(ascii[3] != 'F',"3 was %c",ascii[3]);
fail_if(ascii[4] != '0', "4 was %c",ascii[4]);
fail_if(ascii[5] != '0', "5 was %c",ascii[5]);
fail_if(ascii[6] != 0, "6 was %c",ascii[6]);
END_TEST
START_TEST (test_2hex_empty)
unsigned char bcd[] = {0xF0, 0xFF, 0x00};
char ascii[sizeof bcd * 2 + 1];
ascii[0] = 0xFF;
size_t len = uc_bcd2ascii(bcd, 0, ascii);
fail_if(len != 0, "len is %zu", len);
fail_if(ascii[0] != 0, "0 was %c",ascii[0]);
END_TEST
Suite *bcd_suite(void)
{
Suite *s = suite_create("bcd");
TCase *tc = tcase_create("bcd tests");
tcase_add_test(tc, test_2bcd_1234567890);
tcase_add_test(tc, test_2bcd_empty);
tcase_add_test(tc, test_2bcd_1_filler);
tcase_add_test(tc, test_2bcd_2_filler);
tcase_add_test(tc, test_2bcd_3_filler);
tcase_add_test(tc, test_2bcd_non_digits);
tcase_add_test(tc, test_2bcd_phoneno);
tcase_add_test(tc, test_2bcd_binary);
tcase_add_test(tc, test_2hex_1);
tcase_add_test(tc, test_2hex_2);
tcase_add_test(tc, test_2hex_empty);
suite_add_tcase(s, tc);
return s;
}
+84
View File
@@ -0,0 +1,84 @@
#include <check.h>
#include "ucore_bitvec.h"
START_TEST (test_bitvec_1)
unsigned long s[3] = {0};
struct bitvec v = BITVEC_STATIC_INIT(s);
size_t i;
for(i = 0; i < sizeof s * 8; i++)
fail_if(get_bit(&v, i), "bit %zu is not 0", i);
END_TEST
START_TEST (test_bitvec_2)
unsigned long s[3] = {0};
struct bitvec v = BITVEC_STATIC_INIT(s);
size_t i;
for(i = 0; i < sizeof s * 8; i++)
set_bit(&v, i);
for(i = 0; i < sizeof s * 8; i++)
fail_if(get_bit(&v, i) != 1 , "bit %zu is not 1", i);
END_TEST
START_TEST (test_bitvec_clearbit)
unsigned long s[3] = {-1, -1, -1};
struct bitvec v = BITVEC_STATIC_INIT(s);
size_t i;
for(i = 0; i < sizeof(unsigned long) * 8; i++)
fail_if(get_bit(&v, i) != 1 , "bit %zu is not 1", i);
for(i = 0; i < sizeof(unsigned long) * 8; i++)
clear_bit(&v, i);
for(i = 0; i < sizeof(unsigned long) * 8; i++)
fail_if(get_bit(&v, i) != 0 , "bit %zu is not 0", i);
END_TEST
START_TEST (test_bitvec_set_bits_from_array)
struct bitvec *v = bitvec_new(5);
char a[] = {1, 0,1 ,0, 1};
set_bits_from_array(v,a , 5);
fail_if(get_bit(v, 0) != 1 , "bit 0 is wrong");
fail_if(get_bit(v, 1) != 0 , "bit 1 is wrong");
fail_if(get_bit(v, 2) != 1 , "bit 2 is wrong");
fail_if(get_bit(v, 3) != 0 , "bit 3 is wrong");
fail_if(get_bit(v, 4) != 1 , "bit 4 is wrong");
END_TEST
START_TEST (test_bitvec_setall_clearall)
struct bitvec *v = bitvec_new(511);
size_t i;
set_all(v);
for(i = 0; i < 511; i++)
fail_if(get_bit(v, i) != 1 , "bit %zu is not 1", i);
clear_all(v);
for(i = 0; i < sizeof(unsigned long) * 8; i++)
fail_if(get_bit(v, i) != 0 , "bit %zu is not 0", i);
END_TEST
Suite *bitvec_suite(void)
{
Suite *s = suite_create("bitvec");
TCase *tc = tcase_create("bitvec tests");
tcase_add_test(tc, test_bitvec_1);
tcase_add_test(tc, test_bitvec_2);
tcase_add_test(tc, test_bitvec_set_bits_from_array);
tcase_add_test(tc, test_bitvec_clearbit);
tcase_add_test(tc, test_bitvec_setall_clearall);
suite_add_tcase(s, tc);
return s;
}
+43
View File
@@ -0,0 +1,43 @@
#include <check.h>
#include "ucore_utils.h"
struct Inner {
int x;
int y;
};
struct Outer {
int tag1;
int tag2;
struct Inner inner;
int tag3;
};
START_TEST (test_container_of)
struct Outer outer = {
.tag1 = 1,
.tag2 = 2,
.inner = {
.x = 1234,
.y = 5678
}
};
struct Inner *innerp = &outer.inner;
struct Outer *outerp = CONTAINER_OF(innerp, struct Outer, inner);
fail_if(outerp != &outer);
END_TEST
Suite *container_of_suite(void)
{
Suite *s = suite_create("container_of");
TCase *tc = tcase_create("container_of tests");
tcase_add_test(tc, test_container_of);
suite_add_tcase(s, tc);
return s;
}
+193
View File
@@ -0,0 +1,193 @@
#include <check.h>
#include <string.h>
#include "ucore_string.h"
START_TEST (test_uc_hex_encode_1)
uint8_t binary[] = {0xff};
char hex[3] = "";
uc_hex_encode(binary, 1, hex);
fail_if(strcmp(hex,"FF") != 0);
END_TEST
START_TEST (test_uc_hex_encode_2)
uint8_t binary[] = {127, 128, 129};
char hex[4] = "";
uc_hex_encode(binary, sizeof binary, hex);
fail_if(strcmp(hex,"7F8081") != 0, "was %s", hex);
END_TEST
START_TEST (test_uc_hex_encode_3)
uint8_t binary[] = {0, 1, 9, 11};
char hex[5] = "";
uc_hex_encode(binary, sizeof binary, hex);
fail_if(strcmp(hex,"0001090B") != 0, "was %s", hex);
END_TEST
START_TEST (test_uc_hex_encode_zero_len)
uint8_t binary[1] = {0xff};
char hex[3] = "aa";
uc_hex_encode(binary, 0, hex);
fail_if(hex[0] != 0);
fail_if(hex[1] != 'a');
END_TEST
START_TEST (test_uc_hex_decode_1)
char hex[] = "1F";
uint8_t binary[2] = {0x11,0x22};
uint8_t *res;
res = uc_hex_decode(hex, 2, binary);
fail_if(binary[0] != 0x1f);
fail_if(binary[1] != 0x22);
fail_if(res != binary + 1, "binary %p, res %p", &binary[0], res);
END_TEST
START_TEST (test_uc_hex_decode_2)
char hex[] = "00FF80";
uint8_t binary[4] = {0x11, 0x11, 0x11};
uint8_t *res;
res = uc_hex_decode(hex, 6, binary);
fail_if(binary[0] != 0x00);
fail_if(binary[1] != 0xFF);
fail_if(binary[2] != 0x80);
fail_if(res != binary + 3, "binary %p, res %p", &binary[0], res);
END_TEST
START_TEST (test_uc_hex_decode_zero_length)
char hex[] = "00FF80";
uint8_t binary[4] = {0x11, 0x11, 0x11};
uint8_t *res;
res = uc_hex_decode(hex, 0, binary);
fail_if(binary[0] != 0x11);
fail_if(binary[1] != 0x11);
fail_if(binary[2] != 0x11);
fail_if(res != binary);
END_TEST
START_TEST (test_uc_hex_decode_empty_string)
char hex[] = "";
uint8_t binary[4] = {0x11, 0x11, 0x11};
uint8_t *res;
res = uc_hex_decode(hex, 2, binary);
fail_if(binary[0] != 0x11);
fail_if(binary[1] != 0x11);
fail_if(binary[2] != 0x11);
fail_if(res != binary);
END_TEST
START_TEST (test_uc_hex_decode_odd_length)
char hex[] = "33FF80";
uint8_t binary[4] = {0x11, 0x11, 0x11};
uint8_t *res;
res = uc_hex_decode(hex, 3, binary);
fail_if(binary[0] != 0x33);
fail_if(binary[1] != 0x11);
fail_if(binary[2] != 0x11);
fail_if(res != &binary[1]);
END_TEST
START_TEST (test_uc_hex_decode_invalid)
char hex[] = "TEST ";
uint8_t binary[4] = {0x11, 0x11, 0x11};
uint8_t *res;
res = uc_hex_decode(hex, 3, binary);
fail_if(binary[0] != 0x11);
fail_if(binary[1] != 0x11);
fail_if(binary[2] != 0x11);
fail_if(res != NULL);
END_TEST
START_TEST (test_uc_hex_encode_delim_1)
uint8_t binary[4] = {0xFF, 0x00, 0x7F, 0x0A};
char hex[17] = "";
char *res;
res = uc_hex_encode_delim(binary, sizeof binary, hex, sizeof hex, " ");
fail_if(strcmp(hex, "FF 00 7F 0A ") != 0, "hex was '%s'", hex);
fail_if(res != hex + 12);
END_TEST
START_TEST (test_uc_hex_encode_delim_2)
uint8_t binary[] = {0xFF, 0x00};
char hex[8] = "";
char *res;
res = uc_hex_encode_delim(binary, sizeof binary, hex, sizeof hex, " \n");
fail_if(strcmp(hex, "FF \n00 ") != 0, "hex was '%s'", hex);
fail_if(res != hex + 8);
END_TEST
START_TEST (test_uc_hex_encode_delim_zero_len)
uint8_t binary[] = {0xFF, 0x00};
char hex[8] = "......";
char *res;
res = uc_hex_encode_delim(binary, 0, hex, sizeof hex, " \n");
fail_if(strcmp(hex, "") != 0, "hex was '%s'", hex);
fail_if(res != hex);
END_TEST
Suite *hex_suite(void)
{
Suite *s = suite_create("hex");
TCase *tc = tcase_create("hex tests");
tcase_add_test(tc, test_uc_hex_encode_1);
tcase_add_test(tc, test_uc_hex_encode_2);
tcase_add_test(tc, test_uc_hex_encode_3);
tcase_add_test(tc, test_uc_hex_encode_zero_len);
tcase_add_test(tc, test_uc_hex_encode_delim_1);
tcase_add_test(tc, test_uc_hex_encode_delim_2);
tcase_add_test(tc, test_uc_hex_encode_delim_zero_len);
tcase_add_test(tc, test_uc_hex_decode_1);
tcase_add_test(tc, test_uc_hex_decode_2);
tcase_add_test(tc, test_uc_hex_decode_zero_length);
tcase_add_test(tc, test_uc_hex_decode_odd_length);
tcase_add_test(tc, test_uc_hex_decode_invalid);
tcase_add_test(tc, test_uc_hex_decode_empty_string);
suite_add_tcase(s, tc);
return s;
}
+403
View File
@@ -0,0 +1,403 @@
#include <check.h>
#include "ucore_pack.h"
START_TEST (test_pack16_le_1)
uint16_t v = 0x1234;
uint8_t r[2];
uc_pack_16_le(v,r);
fail_if(r[0] != 0x34,"was 0x%x",r[0]);
fail_if(r[1] != 0x12,"was 0x%x",r[1]);
END_TEST
START_TEST (test_pack16_le_2)
uint16_t v = 0xFEEF;
uint8_t r[2];
uc_pack_16_le(v,r);
fail_if(r[0] != 0xEF,"was 0x%x",r[0]);
fail_if(r[1] != 0xFE,"was 0x%x",r[1]);
END_TEST
START_TEST (test_pack16_be_1)
uint16_t v = 0x1234;
uint8_t r[2];
uc_pack_16_be(v,r);
fail_if(r[0] != 0x12,"was 0x%x",r[0]);
fail_if(r[1] != 0x34,"was 0x%x",r[1]);
END_TEST
START_TEST (test_pack16_be_2)
uint16_t v = 0xFEEF;
uint8_t r[2];
uc_pack_16_be(v, r);
fail_if(r[0] != 0xFE,"was 0x%x",r[0]);
fail_if(r[1] != 0xEF,"was 0x%x",r[1]);
END_TEST
START_TEST (test_unpack16_le_1)
uint16_t v;
uint8_t r[2] = {0x12, 0x34};
v = uc_unpack_16_le(r);
fail_if(v != 0x3412,"was 0x%x",v);
END_TEST
START_TEST (test_unpack16_le_2)
uint16_t v;
uint8_t r[2] = {0xFE, 0xEF};
v = uc_unpack_16_le(r);
fail_if(v != 0xEFFE,"was 0x%x",v);
END_TEST
START_TEST (test_unpack16_be_1)
uint16_t v;
uint8_t r[2] = {0x12, 0x34};
v = uc_unpack_16_be(r);
fail_if(v != 0x1234,"was 0x%x",v);
END_TEST
START_TEST (test_unpack16_be_2)
uint16_t v;
uint8_t r[2] = {0xFE, 0xEF};
v = uc_unpack_16_be(r);
fail_if(v != 0xFEEF,"was 0x%x",v);
END_TEST
START_TEST (test_pack24_le_1)
uint32_t v = 0x123456;
uint8_t r[3];
uc_pack_24_le(v,r);
fail_if(r[0] != 0x56,"was 0x%x",r[0]);
fail_if(r[1] != 0x34,"was 0x%x",r[1]);
fail_if(r[2] != 0x12,"was 0x%x",r[2]);
END_TEST
START_TEST (test_pack24_le_2)
uint32_t v = 0xF8F7F6;
uint8_t r[3];
uc_pack_24_le(v,r);
fail_if(r[0] != 0xF6,"was 0x%x",r[0]);
fail_if(r[1] != 0xF7,"was 0x%x",r[1]);
fail_if(r[2] != 0xF8,"was 0x%x",r[2]);
END_TEST
START_TEST (test_pack24_be_1)
uint32_t v = 0x123456;
uint8_t r[3];
uc_pack_24_be(v,r);
fail_if(r[0] != 0x12,"was 0x%x",r[0]);
fail_if(r[1] != 0x34,"was 0x%x",r[1]);
fail_if(r[2] != 0x56,"was 0x%x",r[2]);
END_TEST
START_TEST (test_pack24_be_2)
uint32_t v = 0xF8F7F6;
uint8_t r[3];
uc_pack_24_be(v,r);
fail_if(r[0] != 0xF8,"was 0x%x",r[0]);
fail_if(r[1] != 0xF7,"was 0x%x",r[1]);
fail_if(r[2] != 0xF6,"was 0x%x",r[2]);
END_TEST
START_TEST (test_pack32_le_1)
uint32_t v = 0x12345678;
uint8_t r[4];
uc_pack_32_le(v,r);
fail_if(r[0] != 0x78,"was 0x%x",r[0]);
fail_if(r[1] != 0x56,"was 0x%x",r[1]);
fail_if(r[2] != 0x34,"was 0x%x",r[2]);
fail_if(r[3] != 0x12,"was 0x%x",r[3]);
END_TEST
START_TEST (test_pack32_le_2)
uint32_t v = 0xF8F7F6F4;
uint8_t r[4];
uc_pack_32_le(v,r);
fail_if(r[0] != 0xF4,"was 0x%x",r[0]);
fail_if(r[1] != 0xF6,"was 0x%x",r[1]);
fail_if(r[2] != 0xF7,"was 0x%x",r[2]);
fail_if(r[3] != 0xF8,"was 0x%x",r[3]);
END_TEST
START_TEST (test_pack32_be_1)
uint32_t v = 0x12345678;
uint8_t r[4];
uc_pack_32_be(v,r);
fail_if(r[3] != 0x78,"was 0x%x",r[3]);
fail_if(r[2] != 0x56,"was 0x%x",r[2]);
fail_if(r[1] != 0x34,"was 0x%x",r[1]);
fail_if(r[0] != 0x12,"was 0x%x",r[0]);
END_TEST
START_TEST (test_pack32_be_2)
uint32_t v = 0xF8F7F6F4;
uint8_t r[4];
uc_pack_32_be(v,r);
fail_if(r[3] != 0xF4,"was 0x%x",r[3]);
fail_if(r[2] != 0xF6,"was 0x%x",r[2]);
fail_if(r[1] != 0xF7,"was 0x%x",r[1]);
fail_if(r[0] != 0xF8,"was 0x%x",r[0]);
END_TEST
START_TEST (test_unpack24_le_1)
uint32_t v;
uint8_t r[3] = {0x12, 0x34, 0x56 };
v = uc_unpack_24_le(r);
fail_if(v != 0x563412,"was 0x%x",v);
END_TEST
START_TEST (test_unpack24_le_2)
uint32_t v;
uint8_t r[4] = {0xF8, 0xF7, 0xF6};
v = uc_unpack_24_le(r);
fail_if(v != 0xF6F7F8,"was 0x%x",v);
END_TEST
START_TEST (test_unpack24_be_1)
uint32_t v;
uint8_t r[3] = {0x12, 0x34, 0x56 };
v = uc_unpack_24_be(r);
fail_if(v != 0x123456,"was 0x%x",v);
END_TEST
START_TEST (test_unpack24_be_2)
uint32_t v;
uint8_t r[4] = {0xF8, 0xF7, 0xF6};
v = uc_unpack_24_be(r);
fail_if(v != 0xF8F7F6,"was 0x%x",v);
END_TEST
START_TEST (test_unpack32_le_1)
uint32_t v;
uint8_t r[4] = {0x12, 0x34, 0x56, 0x78};
v = uc_unpack_32_le(r);
fail_if(v != 0x78563412,"was 0x%x",v);
END_TEST
START_TEST (test_unpack32_le_2)
uint32_t v;
uint8_t r[4] = {0xF8, 0xF7, 0xF6, 0xF4 };
v = uc_unpack_32_le(r);
fail_if(v != 0xF4F6F7F8,"was 0x%x",v);
END_TEST
START_TEST (test_unpack32_be_1)
uint32_t v;
uint8_t r[4] = {0x12, 0x34, 0x56, 0x78};
v = uc_unpack_32_be(r);
fail_if(v != 0x12345678,"was 0x%x",v);
END_TEST
START_TEST (test_unpack32_be_2)
uint32_t v;
uint8_t r[4] = {0xF8, 0xF7, 0xF6, 0xF4 };
v = uc_unpack_32_be(r);
fail_if(v != 0xF8F7F6F4,"was 0x%x",v);
END_TEST
START_TEST (test_pack64_le_1)
uint64_t v = 0x1122334455667788ULL;
uint8_t r[8] = {};
uc_pack_64_le(v, r);
fail_if(r[0] != 0x88,"was 0x%x",r[0]);
fail_if(r[1] != 0x77,"was 0x%x",r[1]);
fail_if(r[2] != 0x66,"was 0x%x",r[2]);
fail_if(r[3] != 0x55,"was 0x%x",r[3]);
fail_if(r[4] != 0x44,"was 0x%x",r[4]);
fail_if(r[5] != 0x33,"was 0x%x",r[5]);
fail_if(r[6] != 0x22,"was 0x%x",r[6]);
fail_if(r[7] != 0x11,"was 0x%x",r[7]);
END_TEST
START_TEST (test_pack64_le_2)
uint64_t v = 0xFFFEFDFCFBFAF9F8ULL;
uint8_t r[8] = {};
uc_pack_64_le(v, r);
fail_if(r[0] != 0xF8,"was 0x%x",r[0]);
fail_if(r[1] != 0xF9,"was 0x%x",r[1]);
fail_if(r[2] != 0xFA,"was 0x%x",r[2]);
fail_if(r[3] != 0xFB,"was 0x%x",r[3]);
fail_if(r[4] != 0xFC,"was 0x%x",r[4]);
fail_if(r[5] != 0xFD,"was 0x%x",r[5]);
fail_if(r[6] != 0xFE,"was 0x%x",r[6]);
fail_if(r[7] != 0xFF,"was 0x%x",r[7]);
END_TEST
START_TEST (test_unpack64_le_1)
uint64_t v;
uint8_t r[8] = {0x11 ,0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
v = uc_unpack_64_le(r);
fail_if(v != 0x8877665544332211ULL,"was 0x%llx",v);
END_TEST
START_TEST (test_unpack64_le_2)
uint64_t v;
uint8_t r[8] = {0xFF ,0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8};
v = uc_unpack_64_le(r);
fail_if(v != 0xF8F9FAFBFCFDFEFFULL,"was 0x%llx",v);
END_TEST
START_TEST (test_pack64_be_1)
uint64_t v = 0x1122334455667788ULL;
uint8_t r[8] = {};
uc_pack_64_be(v, r);
fail_if(r[0] != 0x11,"was 0x%x",r[0]);
fail_if(r[1] != 0x22,"was 0x%x",r[1]);
fail_if(r[2] != 0x33,"was 0x%x",r[2]);
fail_if(r[3] != 0x44,"was 0x%x",r[3]);
fail_if(r[4] != 0x55,"was 0x%x",r[4]);
fail_if(r[5] != 0x66,"was 0x%x",r[5]);
fail_if(r[6] != 0x77,"was 0x%x",r[6]);
fail_if(r[7] != 0x88,"was 0x%x",r[7]);
END_TEST
START_TEST (test_pack64_be_2)
uint64_t v = 0xFFFEFDFCFBFAF9F8ULL;
uint8_t r[8] = {};
uc_pack_64_be(v, r);
fail_if(r[0] != 0xFF,"was 0x%x",r[0]);
fail_if(r[1] != 0xFE,"was 0x%x",r[1]);
fail_if(r[2] != 0xFD,"was 0x%x",r[2]);
fail_if(r[3] != 0xFC,"was 0x%x",r[3]);
fail_if(r[4] != 0xFB,"was 0x%x",r[4]);
fail_if(r[5] != 0xFA,"was 0x%x",r[5]);
fail_if(r[6] != 0xF9,"was 0x%x",r[6]);
fail_if(r[7] != 0xF8,"was 0x%x",r[7]);
END_TEST
START_TEST (test_unpack64_be_1)
uint64_t v;
uint8_t r[8] = {0x11 ,0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
v = uc_unpack_64_be(r);
fail_if(v != 0x1122334455667788ULL,"was 0x%llx",v);
END_TEST
START_TEST (test_unpack64_be_2)
uint64_t v;
uint8_t r[8] = {0xFF ,0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8};
v = uc_unpack_64_be(r);
fail_if(v != 0xFFFEFDFCFBFAF9F8ULL,"was 0x%llx",v);
END_TEST
Suite *pack_suite(void)
{
Suite *s = suite_create("pack");
TCase *tc = tcase_create("pack tests");
tcase_add_test(tc, test_pack16_le_1);
tcase_add_test(tc, test_pack16_le_2);
tcase_add_test(tc, test_pack16_be_1);
tcase_add_test(tc, test_pack16_be_2);
tcase_add_test(tc, test_unpack16_le_1);
tcase_add_test(tc, test_unpack16_le_2);
tcase_add_test(tc, test_unpack16_be_1);
tcase_add_test(tc, test_unpack16_be_2);
tcase_add_test(tc, test_pack24_le_1);
tcase_add_test(tc, test_pack24_le_2);
tcase_add_test(tc, test_pack24_be_1);
tcase_add_test(tc, test_pack24_be_2);
tcase_add_test(tc, test_unpack24_le_1);
tcase_add_test(tc, test_unpack24_le_2);
tcase_add_test(tc, test_unpack24_be_1);
tcase_add_test(tc, test_unpack24_be_2);
tcase_add_test(tc, test_pack32_le_1);
tcase_add_test(tc, test_pack32_le_2);
tcase_add_test(tc, test_pack32_be_1);
tcase_add_test(tc, test_pack32_be_2);
tcase_add_test(tc, test_unpack32_le_1);
tcase_add_test(tc, test_unpack32_le_2);
tcase_add_test(tc, test_unpack32_be_1);
tcase_add_test(tc, test_unpack32_be_2);
tcase_add_test(tc, test_pack64_le_1);
tcase_add_test(tc, test_pack64_le_2);
tcase_add_test(tc, test_unpack64_le_1);
tcase_add_test(tc, test_unpack64_le_2);
tcase_add_test(tc, test_pack64_be_1);
tcase_add_test(tc, test_pack64_be_2);
tcase_add_test(tc, test_unpack64_be_1);
tcase_add_test(tc, test_unpack64_be_2);
suite_add_tcase(s, tc);
return s;
}
+106
View File
@@ -0,0 +1,106 @@
#include <check.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "ucore_read_file.h"
START_TEST (test_read_file_non_existing_file)
char *content;
size_t len;
int saved_errno;
content = uc_read_file("non existing file 123765", &len, 1000000000);
saved_errno = errno;
fail_if(content != NULL);
fail_if(saved_errno == 0);
END_TEST
START_TEST (test_read_file_simple)
char *content;
const char *filename = "test_read_file_simple";
size_t len;
ssize_t rc;
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
fail_if(fd == -1);
rc = write(fd, "hello", 5);
fail_if(rc != 5, "rc was %ld", (long)rc);
close(fd);
content = uc_read_file(filename, &len, 1000000000);
unlink(filename);
fail_if(content == NULL);
fail_if(len != 5);
fail_if(strlen(content) != 5);
fail_if(strcmp("hello", content) != 0);
END_TEST
START_TEST (test_read_file_greater_than_max)
char *content;
const char *filename = "test_read_file_simple";
size_t len;
ssize_t rc;
int saved_errno;
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
fail_if(fd == -1);
rc = write(fd, "hello", 5);
fail_if(rc != 5, "rc was %ld", (long)rc);
close(fd);
content = uc_read_file(filename, &len, 4);
saved_errno = errno;
unlink(filename);
fail_if(content != NULL);
fail_if(saved_errno != EMSGSIZE, "was %d", saved_errno);
END_TEST
START_TEST (test_read_file_boundary)
char *content;
const char *filename = "test_read_file_boundary";
size_t len;
ssize_t rc;
char buf[1030] = "";
strcpy(&buf[1022], "foobar");
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
fail_if(fd == -1);
rc = write(fd, buf, sizeof buf);
fail_if(rc != sizeof buf, "rc was %ld", (long)rc);
close(fd);
content = uc_read_file(filename, &len, 1000000000);
unlink(filename);
fail_if(content == NULL);
fail_if(len != sizeof buf);
fail_if(strcmp("foobar", &content[1022]) != 0);
free(content);
END_TEST
Suite *read_file_suite(void)
{
Suite *s = suite_create("read_file");
TCase *tc = tcase_create("read_file tests");
tcase_add_test(tc, test_read_file_non_existing_file);
tcase_add_test(tc, test_read_file_simple);
tcase_add_test(tc, test_read_file_greater_than_max);
tcase_add_test(tc, test_read_file_boundary);
suite_add_tcase(s, tc);
return s;
}
+40
View File
@@ -0,0 +1,40 @@
#include <stdlib.h>
#include <getopt.h>
#include <stdio.h>
#include <check.h>
extern Suite *bitvec_suite(void);
extern Suite *bcd_suite(void);
extern Suite *hex_suite(void);
extern Suite *container_of_suite(void);
extern Suite *read_file_suite(void);
extern Suite *pack_suite(void);
int
main (int argc, char *argv[])
{
int xml_output = argc > 1 && strcmp(argv[1], "--xml") == 0;
int number_failed = 0;
SRunner *sr = srunner_create (NULL);
if(xml_output)
srunner_set_xml(sr, "result.xml");
srunner_add_suite(sr, bitvec_suite());
srunner_add_suite(sr, bcd_suite());
srunner_add_suite(sr, hex_suite());
srunner_add_suite(sr, container_of_suite());
srunner_add_suite(sr, read_file_suite());
srunner_add_suite(sr, pack_suite());
srunner_run_all (sr, CK_VERBOSE);
number_failed = srunner_ntests_failed (sr);
srunner_free (sr);
if(number_failed)
printf("ERROR: %d tests failed\n", number_failed);
return (number_failed != 0) ;
}
+111
View File
@@ -0,0 +1,111 @@
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
struct descriptor {
int fd;
SPLAY_ENTRY(descriptor) entry;
};
int descriptor_cmp(struct descriptor *a, struct descriptor *b);
SPLAY_HEAD(descriptors, descriptor);
SPLAY_PROTOTYPE(descriptors, descriptor, entry, descriptor_cmp);
SPLAY_GENERATE(descriptors, descriptor, entry, descriptor_cmp);
struct descriptors entries;
int descriptor_cmp(struct descriptor *a, struct descriptor *b)
{
if(a->fd < b->fd)
return -1;
if(a->fd > b->fd)
return 1;
return 0;
}
void add(int fd)
{
struct descriptor *des = malloc(sizeof *des);
des->fd = fd;
SPLAY_INSERT(descriptors, &entries, des);
}
void find(int fd)
{
struct descriptor des;
struct descriptor *found;
des.fd = fd;
found = SPLAY_FIND(descriptors, &entries, &des);
if(found == NULL)
printf("Not found fd %d\n", fd);
else
printf("Found fd %d (%d)\n", found->fd, fd);
}
void rem(int fd)
{
struct descriptor des;
des.fd = fd;
SPLAY_REMOVE(descriptors, &entries, &des);
}
void iter(void){
struct descriptor *bd;
SPLAY_FOREACH(bd, descriptors, &entries) {
printf("foreach fd %d\n", bd->fd);
}
}
void rem_iter(void){
struct descriptor *bd;
while (!SPLAY_EMPTY(&entries)) {
bd = SPLAY_ROOT(&entries);
SPLAY_REMOVE(descriptors, &entries, bd);
printf("removed fd %d\n", bd->fd);
free(bd);
}
}
void fd_min_max(void)
{
struct descriptor *min_des, *max_des;
min_des = SPLAY_MIN(descriptors, &entries);
max_des = SPLAY_MAX(descriptors, &entries);
if(min_des && max_des)
printf("min fd = %d max fd = %d\n", min_des->fd, max_des->fd);
}
int main(int argc, char *argv[])
{
SPLAY_INIT(&entries);
add(3);
add(4);
add(5);
add(11);
add(64);
add(9);
add(12);
find(11);
find(13);
rem(11);
find(11);
fd_min_max();
iter();
rem_iter();
fd_min_max();
return 0;
}
+17
View File
@@ -0,0 +1,17 @@
#include <stdlib.h>
#include <stdio.h>
#include "ucore_math.h"
int main(int argc, char *argv[])
{
unsigned int a,N;
if(argc < 2) {
printf("Usage %s interger1\n",argv[0]);
return 1;
}
a = atoi(argv[1]);
N = uc_phi_32(a);
printf("phi of %u is %u\n",a,N);
return 0;
}