diff --git a/.gitignore b/.gitignore index 603593c..8c4797f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ log_subdir/ coverage/ install/ libucore-* +src/version.c +.cache/ +compile_commands.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..b635f50 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,15 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${default}", + "${workspaceFolder}/include" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "intelliSenseMode": "macos-clang-arm64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..571ae2e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.associations": { + "*.h": "c", + }, + "C_Cpp.default.includePath": [ + "/opt/homebrew/include/", + "$(workspaceFolder)/include/", + + ], + "C_Cpp.default.cStandard": "gnu99" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7a23ef6 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,19 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "cmake", + "label": "CMake: build", + "command": "build", + "targets": [ + "all" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "detail": "CMake template build task" + } + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f770602 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.12) +project(libucore C) + +execute_process(COMMAND git -C ${CMAKE_SOURCE_DIR} describe --abbrev=5 --dirty --always OUTPUT_VARIABLE version_revision WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_STRIP_TRAILING_WHITESPACE) +cmake_host_system_information(RESULT build_host QUERY HOSTNAME) +set(libucore_VERSION_MAJOR 1) +set(libucore_VERSION_MINOR 0) +set(libucore_VERSION_PATCH 0) +set(libucore_VERSION ${libucore_VERSION_MAJOR}.${libucore_VERSION_MINOR}.${libucore_VERSION_PATCH}.${version_revision}) + +set(CMAKE_VERBOSE_MAKEFILE ON) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wundef -Wcast-qual -Wshadow -Wcast-align -pipe -Wno-unused-parameter -Werror=implicit-function-declaration -Winit-self") +add_definitions(-D_FILE_OFFSET_BITS=64) +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -O2") +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) +option(CODE_COVERAGE "build with code coverage intrumentation" OFF) + +if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) + # Set the property for multi-config generators as well, if applicable + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel) +endif() +set(build_type ${CMAKE_BUILD_TYPE}) +if (CODE_COVERAGE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") + add_definitions(-DCOVERAGE) + set(build_type "${build_type}-coverage") +endif() + +option(BUILD_SANITIZE "build with address sanitizer" OFF) +if (BUILD_SANITIZE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") + set(build_type "${build_type}-sanitize") +endif() + + +include_directories(include) + +add_subdirectory(src) +add_subdirectory(test) +add_subdirectory(include) + diff --git a/Doxyfile b/Doxyfile index df415e7..6edfda1 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1192,7 +1192,7 @@ MATHJAX_EXTENSIONS = # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. -SEARCHENGINE = NO +SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client diff --git a/SConstruct b/SConstruct index efb7a12..922222e 100644 --- a/SConstruct +++ b/SConstruct @@ -66,6 +66,13 @@ AddOption('--stack-protection', help = 'Build with stack protection support' ) +AddOption('--sanitizer', + dest = 'sanitizer', + action='store_true', + default=False, + help = 'Build with gcc sanitizer' +) + AddOption('--32', dest='force32bit', action='store_true', @@ -126,6 +133,10 @@ if GetOption('coverage'): env.Append(CFLAGS = ['--coverage']) env.Append(LINKFLAGS = ['--coverage']) +if GetOption('sanitizer'): + env.Append(CFLAGS = ['-fsanitize=undefined', '-fsanitize=address']) + env.Append(LINKFLAGS = ['-fsanitize=undefined', '-fsanitize=address']) + # Generate substitute dictionary subst_info = dict(('@' + key + '@', version_info[key]) for key in version_info) subst_info['@prefix@'] = prefix @@ -164,4 +175,3 @@ env.Package(target = 'libucore-' + version_info['version_str'] + '.tar.gz', X_RPM_GROUP = 'Development/Libraries' ) -env.Default('src') diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt new file mode 100644 index 0000000..3e8dcd4 --- /dev/null +++ b/include/CMakeLists.txt @@ -0,0 +1 @@ +install(DIRECTORY ucore DESTINATION include) diff --git a/include/ucore/bitvec.h b/include/ucore/bitvec.h index bb5dfe1..493236e 100644 --- a/include/ucore/bitvec.h +++ b/include/ucore/bitvec.h @@ -27,7 +27,7 @@ struct UCBitVec { * Use as * @code * uc_bv_integer v[10]; - * struct UCBitVec v = BITVEC_STATIC_INIT(v); + * struct UCBitVec v = UC_BV_STATIC_INIT(v); * @endcode */ #define UC_BV_STATIC_INIT(vec_data)\ @@ -68,11 +68,16 @@ void uc_bv_set_all(struct UCBitVec *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}; + * int a[] = {0,1,1,1,0}; * set_bits_from_array(v,a,5); * */ void uc_bv_set_bits_from_array(struct UCBitVec *v,const char *array,size_t array_len); +/** Find the index of the first zero bit in the bitvec. + * @param v The bitvec to search + * @return The index of the first zero bit, or -1 if all bits are set + */ +int uc_bv_find_first_zero(const struct UCBitVec *v); #ifdef __cplusplus } diff --git a/include/ucore/iomux_signal.h b/include/ucore/iomux_signal.h index 43e014b..05e18d6 100644 --- a/include/ucore/iomux_signal.h +++ b/include/ucore/iomux_signal.h @@ -2,6 +2,15 @@ #define UC_IOMUX_SIGNAL_H_ #include "ucore/iomux.h" + +/** @addtogroup IOMux + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + /** Callback signature for handling unix signals. * @param mux associated mux * @param signo unix signal number @@ -45,4 +54,10 @@ int iomux_register_unixsignal(struct IOMux *mux, */ int iomux_unregister_unixsignal(struct IOMux *mux, int signo); +#ifdef __cplusplus +} +#endif + +/** @} (addtogroup)*/ + #endif diff --git a/include/ucore/saturating_math.h b/include/ucore/saturating_math.h index 6b9228f..84f9a62 100644 --- a/include/ucore/saturating_math.h +++ b/include/ucore/saturating_math.h @@ -10,10 +10,34 @@ * * multiplication, subtraction and addition operations are provided.*/ +//Use gcc builtins, supported since GCC 5 +#if __GNUC__ >= 5 + +#define UC_SAT_ADD(a, b, type, max_val)\ +({type res ;\ +if (__builtin_add_overflow(a, b, &res)) {\ + res = max_val;}\ +res;}) + + +#define UC_SAT_SUB(a, b, type)\ +({type res ;\ +if (__builtin_sub_overflow(a, b, &res)) {\ + res = 0;}\ +res;}) + +#define UC_SAT_MULT(a, b, type, max_val)\ +({type res ;\ +if (__builtin_mul_overflow(a, b, &res)) {\ + res = max_val;}\ +res;}) + +#else + #define UC_SAT_ADD(a, b, type, max_val)\ ((type)((a) + (b)) >= (a) ? (a) + (b) : (max_val)) -#define UC_SAT_SUB(a, b)\ +#define UC_SAT_SUB(a, b, type)\ ((a) >= (b) ? (a) - (b) : 0) #define UC_SAT_MULT(a, b, type, max_val)\ @@ -21,6 +45,7 @@ (a) <= (max_val) / (b) ? (type) (a) * (type) (b) \ : (max_val)) +#endif static inline uint8_t uc_sat_addu8(uint8_t a, uint8_t b) { @@ -29,7 +54,7 @@ static inline uint8_t uc_sat_addu8(uint8_t a, uint8_t b) static inline uint8_t uc_sat_subu8(uint8_t a, uint8_t b) { - return UC_SAT_SUB(a, b); + return UC_SAT_SUB(a, b, uint8_t); } static inline uint8_t uc_sat_multu8(uint8_t a, uint8_t b) @@ -44,7 +69,7 @@ static inline uint16_t uc_sat_addu16(uint16_t a, uint16_t b) static inline uint16_t uc_sat_subu16(uint16_t a, uint16_t b) { - return UC_SAT_SUB(a, b); + return UC_SAT_SUB(a, b, uint16_t); } static inline uint16_t uc_sat_multu16(uint16_t a, uint16_t b) @@ -59,7 +84,7 @@ static inline uint32_t uc_sat_addu32(uint32_t a, uint32_t b) static inline uint32_t uc_sat_subu32(uint32_t a, uint32_t b) { - return UC_SAT_SUB(a, b); + return UC_SAT_SUB(a, b, uint32_t); } static inline uint32_t uc_sat_multu32(uint32_t a, uint32_t b) @@ -74,7 +99,7 @@ static inline uint64_t uc_sat_addu64(uint64_t a, uint64_t b) static inline uint64_t uc_sat_subu64(uint64_t a, uint64_t b) { - return UC_SAT_SUB(a, b); + return UC_SAT_SUB(a, b, uint64_t); } static inline uint64_t uc_sat_multu64(uint64_t a, uint64_t b) diff --git a/include/ucore/slot_allocator.h b/include/ucore/slot_allocator.h new file mode 100644 index 0000000..d0cdc7f --- /dev/null +++ b/include/ucore/slot_allocator.h @@ -0,0 +1,112 @@ +#ifndef UC_SLOT_ALLOCATOR_H_ +#define UC_SLOT_ALLOCATOR_H_ + +#include +#include +#include "ucore/bitvec.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** @file + * Fixed size slot memory allocator + * + * UCSlotAlloc is used to allocate fixed slots of memory from a pre-allocated + * piece of memory. + * + * The main use case is to keep allocated memory in a contiguous block for use + * maximum number of objects(slots) is known and relatively small. More than 131072 slots + * is not recommended. + * + * Note that this allocator is not thread safe. + * + * A bitmap is used to track which slots are allocated. + */ + + + +typedef struct UCSlotAlloc UCSlotAlloc; +struct UCSlotAlloc { + const uint32_t slot_size; + const uint32_t num_slots; + struct UCBitVec bitmap; + uint8_t *slots; +}; + + +/** Initialize a UCSlotAlloc with an array as the backing memory to allocate slots from. + * The macro can be used at local scope to allocate memory automatic (stack) storage, + * or at global scope where the backin array will have static storage duration + * + * Use as: + * @code + * UC_SLOT_ALLOC_DEF(my_allocator, sizeof foo, 1024) + * struct foo *foo = uc_slot_alloc(&my_allocator); + * if (foo == NULL) { + * // out of memory + * } else { + * .. use foo + * uc_slot_free(&my_allocator, foo); + * } + * @endcode + * + * @param var_name Variable name for the allocator + * @param v slot_size Memory size allocated for each slot + * @param v num_slots Number of slots to reserve memory for +*/ +#define UC_SLOT_ALLOC_DEF(var_name, slot_size_, num_slots_) \ +struct {\ + uc_bv_integer bitmap[UC_BV_LEN((num_slots_))]; \ + uint8_t memory[(num_slots_) * (slot_size_)] __attribute__((aligned)); \ +} var_name ## _memory = { \ +}; \ +UCSlotAlloc var_name = { \ + .slot_size = (slot_size_), \ + .num_slots = (num_slots_), \ + .bitmap = UC_BV_STATIC_INIT(var_name ## _memory.bitmap), \ + .slots = var_name ## _memory.memory \ +}; + +/** Similar to UC_SLOT_ALLOC_DEF but allows you to specify the backing memory that must + * be atleast as large as num_slots * slot_size. Note that an array of num_slots * slot_size + * bits is also allocated for the bitmap with this definition + */ +#define UC_SLOT_ALLOC_DEF_EX(var_name, slot_size_, num_slots_, memory) \ +uc_bv_integer var_name ## _bitmap[UC_BV_LEN((num_slots_))] = {}; \ +UCSlotAlloc var_name = { \ + .slot_size = (slot_size_), \ + .num_slots = (num_slots_), \ + .bitmap = UC_BV_STATIC_INIT(var_name ## _bitmap), \ + .slots = (memory) \ +}; + +/** Allocate a memory slot + * + * @param sa The allocator to allocate from + * @return A pointer to the memory slot that's sa.slot_size big, or NULL if + * all slots are allocated + */ +void *uc_slot_alloc(UCSlotAlloc *sa); + + +/** Free a memory slot previously returned from uc_slot_alloc() + * + * @param sa The allocator to free from. + * @param slot The memory slot to free. Passing a NULL pointer is undefined behavior + */ +void uc_slot_free(UCSlotAlloc *restrict sa, void *restrict slot); + +/** uc_slot_free() where the slot can be a NULL pointer */ +#define uc_slot_free_safe(sa, slot) \ +do { \ + if ((slot) != NULL) { \ + uc_slot_free((sa), (slot)); \ + } \ +} while (0) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ucore/string.h b/include/ucore/string.h index ccdb53d..b60eac9 100644 --- a/include/ucore/string.h +++ b/include/ucore/string.h @@ -96,7 +96,8 @@ char* uc_sprintbs(char *result, unsigned short value); /** Like http://swtch.com/plan9port/man/man3/getfields.html */ -int getfields(char *str, char **args, int max, int mflag, const char *set); +int uc_getfields(char *str, char **args, int max, int mflag, const char *sep); +int uc_gettokens(char *str, char **args, int max, const char *sep); //Converts bytes to a human representable test, (i.e. 12kB, 160 MB 1.78 GB etc.) ///result should be at least of size 12, diff --git a/include/ucore/strvec.h b/include/ucore/strvec.h index 4bbe887..d4cf7f9 100644 --- a/include/ucore/strvec.h +++ b/include/ucore/strvec.h @@ -38,7 +38,7 @@ void uc_strv_init(struct UCStrv *strv); int uc_strv_grow(struct UCStrv *strv, size_t cnt); /** - * Expand the UCStrv to hold attleast 1 more item if needed + * If needed, grow the UCStrv to hold atleast 1 more item. * * @param strv UCStrv to expand * @return 0 on success, otherwise failure @@ -46,7 +46,7 @@ int uc_strv_grow(struct UCStrv *strv, size_t cnt); int uc_strv_check_expand(struct UCStrv *strv); /** - * Append a string to the UCStrv, the string will be copied in + * Append a string to the UCStrv, the string will be copied in. * * @param strv UCStrv to append to * @param str String to append, the string will be copied. @@ -55,7 +55,7 @@ int uc_strv_check_expand(struct UCStrv *strv); int uc_strv_append(struct UCStrv *strv, const char *restrict str); /** - * Append a string to the strvec, nocopy variang. + * Append a string to the strvec without making a copy of the string. * The string shold be dynamically allocated, as * destroying the UCStrv will free() all items. * @@ -67,7 +67,7 @@ int uc_strv_append_nocopy(struct UCStrv *strv, char *restrict str); /** * Append a NULL pointer to the UCStrv, (cnt is not increased, - * so another _appended item will overwrite this NULL terminator) + * so another appended item will overwrite this NULL terminator) * * @param strv UCStrv to append to * @return 0 on success, otherwise failure @@ -101,6 +101,11 @@ void uc_strv_destroy(struct UCStrv *strv); */ int uc_strv_append_all(struct UCStrv *restrict a, struct UCStrv *restrict b, int copy); +/** Reverse the order of strings in a UCStrv + * + * @param strv strv to reverse. + */ +void uc_strv_reverse(struct UCStrv *strv); #ifdef __cplusplus } #endif diff --git a/include/ucore/timers.h b/include/ucore/timers.h index 4385298..00f1563 100644 --- a/include/ucore/timers.h +++ b/include/ucore/timers.h @@ -96,6 +96,8 @@ void uc_timers_init_ex(struct UCTimers *t, struct UCoreClock *uclock); * will be called when the timer expires, and the timer is removed from the engine * User is responsible for the lifetime and memory of the UCTimer, which must exist until * te timer is fired or removed. + * If the timer has previously been added, it will be removed first. So there + * is no need to call uc_timers_remove() to "re-schedule" a timer. * * @param timers timer engine to add timer to. * @param timer timer to add diff --git a/include/ucore/utils.h b/include/ucore/utils.h index 614b6bc..1a0b7f7 100644 --- a/include/ucore/utils.h +++ b/include/ucore/utils.h @@ -30,7 +30,7 @@ // 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*: @@ -55,7 +55,7 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \ /** * Test if x is a power of 2 - * + * * @param x value, must be an unsigned type * @return 1 if x is a power of 20, 0 if it is not */ @@ -90,7 +90,7 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \ * * @param x numerator, must be positive * @param y denominator - * @return x/y rounded up + * @return x/y rounded up */ #define UC_DIV_ROUND_UP(x, y) (((x) + ((y) - 1))/(y)) @@ -103,7 +103,7 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \ * @param y denominator * @return x rounded up to nearest multiple of y */ -#define UC_ROUND_UP(x, y) (UC_DIV_ROUND_UP((x), (y)) * (y)) +#define UC_ROUND_UP(x, y) (UC_DIV_ROUND_UP((x), (y)) * (y)) /** * Round x down to nearest multiple of y diff --git a/include/ucore/wqueue.h b/include/ucore/wqueue.h index 3a460dd..4e64459 100644 --- a/include/ucore/wqueue.h +++ b/include/ucore/wqueue.h @@ -4,6 +4,17 @@ #include "mbuf.h" #include "iomux.h" +/** @addtogroup IOMux + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return code from users write callback + */ enum UC_WQ_RESULT { /** INdicates the MBuf was fully processed and can be freed*/ UC_WQ_DONE = 1, @@ -13,6 +24,8 @@ enum UC_WQ_RESULT { UC_WQ_ABORT = -1 }; +struct UCWQueue; + /** * Callback that will be called when data can be written to the fd. * The return value from this function must be strictly followed. @@ -38,7 +51,9 @@ enum UC_WQ_RESULT { * for this event. * */ -typedef enum UC_WQ_RESULT (*wqueue_write_cb)(struct IOMux *mux, struct IOMuxFD *fd, struct MBuf *mbuf); +typedef enum UC_WQ_RESULT (*wqueue_write_cb)(struct IOMux *mux, + struct UCWQueue *wqueue, + struct MBuf *mbuf); /** * Callback when read events are indicated. @@ -49,17 +64,43 @@ typedef enum UC_WQ_RESULT (*wqueue_write_cb)(struct IOMux *mux, struct IOMuxFD * * @param mux associated IOMux * @param the fd of the current wqueue */ -typedef enum UC_WQ_RESULT (*wqueue_read_cb)(struct IOMux *mux, struct IOMuxFD *fd); +typedef enum UC_WQ_RESULT (*wqueue_read_cb)(struct IOMux *mux, + struct UCWQueue *wqueue); -/** Represents a queue of data to write. +/** + * Callback to free a MBuf once it's fully written. + * @param the fd of the current wqueue + */ +typedef void (*wqueue_free_mbuf_cb)(struct MBuf *mbuf); + +/** + * Represents a queue of data to write. + * UCWQueue replaces a raw IOMuxFD, and manages a queue + * of data to write, held as a list of struct MBuf. + * See also uc_wqueue_init + * */ struct UCWQueue { + /** Underlying IOMuxFD. This member needs to be registered + * with an IOMux, see the description of uc_wqueue_init + */ struct IOMuxFD fd; + /** Linked list of struct MBuf + */ struct TailQ queue; + /** Associated mux + */ struct IOMux *mux; + /** Users callback for read events + */ wqueue_read_cb read_cb; + /** Users callback for write events + */ wqueue_write_cb write_cb; - + /** Function used to free an MBuf - default is uc_mbuf_free()*/ + wqueue_free_mbuf_cb free_cb; + /** Current number of queued struct MBuf + */ unsigned int queue_len; }; @@ -120,4 +161,10 @@ int uc_wqueue_enqueue(struct UCWQueue *wqueue, struct MBuf *mbuf); */ int uc_wqueue_flush(struct UCWQueue *wqueue); +#ifdef __cplusplus +} +#endif + +/** @} (addtogroup)*/ + #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..2676c73 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,14 @@ +configure_file ( +"version.c.in" +"version.c" +) +file(GLOB SOURCE_FILES *.c) + +add_library( +ucore SHARED +${SOURCE_FILES} +"${PROJECT_BINARY_DIR}/src/version.c" +) +set_target_properties(ucore PROPERTIES SOVERSION 1 VERSION 1.0.0) +target_link_libraries(ucore Threads::Threads) +install (TARGETS ucore DESTINATION lib) diff --git a/src/SConscript b/src/SConscript index 7d060a3..ed74ad0 100644 --- a/src/SConscript +++ b/src/SConscript @@ -21,3 +21,5 @@ ucore_env.Alias('install', ucore_env.Install(os.path.join(prefix, 'lib'), [ucore_staticlib])) ucore_env.Alias('install', ucore_env.InstallVersionedLib(os.path.join(prefix, 'lib'), [ucore_sharedlib])) + +ucore_env.Default([ucore_staticlib, ucore_sharedlib]) diff --git a/src/bitvec.c b/src/bitvec.c index 6fb5892..9644f58 100644 --- a/src/bitvec.c +++ b/src/bitvec.c @@ -2,6 +2,7 @@ #include #include #include +#include "ucore/utils.h" #include "ucore/bitvec.h" #ifdef __GNUC__ @@ -12,6 +13,8 @@ #define unlikely(expr) (expr) #endif +UC_STATIC_ASSERT(CHAR_BIT % 8 == 0); + static inline int bit_index(int b) { return b / (sizeof(uc_bv_integer) * CHAR_BIT); @@ -41,7 +44,7 @@ struct UCBitVec *uc_bv_new(size_t nbits) void uc_bv_free(struct UCBitVec *v) { - if (v) { + if (likely(v != NULL)) { free(v); } } @@ -88,3 +91,18 @@ void uc_bv_set_all(struct UCBitVec *v) memset(v->vec,0xff,v->vec_len * sizeof(uc_bv_integer)); } +int uc_bv_find_first_zero(const struct UCBitVec *v) +{ + const size_t bits_per_word = sizeof(uc_bv_integer) * CHAR_BIT; + + for (size_t i = 0; i < v->vec_len; i++) { + uc_bv_integer inverted = ~v->vec[i]; + + if (inverted != 0) { + int bit_pos = __builtin_ffsl(inverted) - 1; // ffsl returns 1-based index + return (int)(i * bits_per_word + bit_pos); + } + } + + return -1; +} diff --git a/src/clock.c b/src/clock.c index bfdbcb7..8813e64 100644 --- a/src/clock.c +++ b/src/clock.c @@ -32,7 +32,7 @@ static void uc_cached_clock_now(const struct UCoreClock *uclock, struct timeval *tv) { const struct UCoreCachedClock *cached_clock; - cached_clock = UC_CONST_CONTAINER_OF(uclock, const struct UCoreCachedClock, clock), + cached_clock = UC_CONST_CONTAINER_OF(uclock, struct UCoreCachedClock, clock), *tv = cached_clock->cache; } @@ -55,7 +55,7 @@ void uc_cached_clock_update(struct UCoreCachedClock *uclock) static void uc_settable_clock_now(const struct UCoreClock *uclock, struct timeval *tv) { const struct UCoreSettableClock *cached_clock; - cached_clock = UC_CONST_CONTAINER_OF(uclock, const struct UCoreSettableClock, clock), + cached_clock = UC_CONST_CONTAINER_OF(uclock, struct UCoreSettableClock, clock), *tv = cached_clock->now; } diff --git a/src/cmd/cmd.c b/src/cmd/cmd.c index 9459958..9734873 100644 --- a/src/cmd/cmd.c +++ b/src/cmd/cmd.c @@ -1,54 +1,788 @@ #include - +#include +#include +#include +#include +#include +#include "ucore/string.h" +#include "ucore/strvec.h" +#include "ucore/utils.h" +#include "ucore/backtrace.h" +// enum UCCmdRc { - /**Executed ok */ - UC_CMD_OK, + UC_CMDRC_OK, /**Executed with warning */ - UC_CMD_WARNING, - /*Not executed, incomplete command */ - UC_CMD_INCOMPLETE, + UC_CMDRC_WARNING, + /*incomplete command */ + UC_CMDRC_INCOMPLETE, + /*Command cann't uniquely be distinguished */ + UC_CMDRC_AMBIGUOUS, + /* Command doesn't exist*/ + UC_CMDRC_NOT_FOUND, /*Not executed, generic error */ - UC_CMD_ERROR, + UC_CMDRC_ERROR, }; -typedef enum UCCmdRc (*uc_cmd_handler)(int narg, char *args[]); -typedef void (*uc_cmd_write_cfg)(void); -#define UC_CMD_FL_HIDDEN (1 << 0) - -struct UCCmdNode; -struct UCCmdDef; - -struct UCCmdSettings { - const char *name; - const char *version; - const char *boot_cfg_file; - - struct UCCmdNode *initial_node; - struct UCCmdNode *node_head; +enum UCCmdType { + UC_CMD_ROOT = 1, + UC_CMD_KEYWORD, + UC_CMD_LIST, + UC_CMD_STRING, + UC_CMD_END, }; -struct UCCmdNode { - int id; - uc_cmd_write_cfg write_func; - struct UCCmdDef *cmd_head; //linked list of UCCmdDef - struct UCCmdNode *next; +struct UCCmdWord { + char *word; + char *descr; }; +struct UCCmdList { + struct UCStrv words; + struct UCStrv descrs; +}; + +struct UCCmdArgs; +typedef enum UCCmdRc (*UCCmdHandler)(const struct UCCmdArgs *args); + struct UCCmdDef { const char *cmd; - const char **help; - size_t cmd_len; - uc_cmd_handler cb; + const char *help; + UCCmdHandler callback; uint32_t flags; +}; - struct UCCmdDef *next; +struct UCCmdArgs { + struct UCStrv argv; + const struct UCCmdDef *cmd; + void *ctx; +}; + +struct UCCmdRunner; +typedef int (*UCCmdRootExit)(struct UCCmdRunner *r, int current_id, void *ctx); +struct UCCmdRoot { + int node_id; + UCCmdRootExit exit_callback; +}; + +/** + * Command are broken into words and inserted into a tree. + * the 3 commands: + * show all + * date + * show all bottles + * Results in the tree: + * + * +--------+ child +--------+ child +-------+ child +-----+ + * | root |------->| show |------->| all |------>| END | + * +--------+ +--------+ +-------+ +-----+ + * | next | next + * V V + * +--------+ child +-----+ +--------+ child +-----+ + * | date |-----> | END | | bottles|------>| END | + * +--------+ +-----+ +--------+ +-----+ + * + * END nodes are complete commands. Other child/next pointers will be nULL + */ + +struct UCCmdNode { + enum UCCmdType type; + union { + struct UCCmdWord word; + struct UCCmdList list; + const struct UCCmdDef *cmd; + const struct UCCmdRootExit *root; + } data; + uint32_t flags; + struct UCCmdNode *next; //next at same level + struct UCCmdNode *child; + struct UCCmdNode *parent; +}; + +struct UCCmdRunner { + struct UCCmdNode *current_root; + struct UCCmdNode _root; +}; +//max words in a single command +#define UC_CMD_MAX_WORDS 32 + +struct UCCmdTokenizer { + char *cmd_copy; + char *cmd_words[UC_CMD_MAX_WORDS]; + int num_words; }; -void uc_cmd_init(const char *app_name, const char *version); -int uc_cmd_read_config(const char *filename); -void uc_cmd_set_configfile(const char *filename); -void uc_cmd_add_cmd(struct UCCmdDef *cmd, int parent_node_id); -void uc_cmd_set_default_node(int node_id); +void +print_args(const struct UCStrv *args); +static int uc_str_empty(const char *str) +{ + while (*str) { + if (!isspace(*str++)) { + return 0; + } + } + return 0; +} + +static int +uc_cmd_type_is_variable(enum UCCmdType type) +{ + return type == UC_CMD_LIST || + type == UC_CMD_STRING; +} + +static void +uc_cmd_tokenize(struct UCCmdTokenizer *t, const char *cmd, const char *delim) +{ + + t->num_words = 0; + t->cmd_copy = strdup(cmd); + if (t->cmd_copy == NULL) { + assert(t->cmd_copy); + return; + } + + if (delim == NULL) { + delim = "\r\n\t\v "; + } + + t->num_words = uc_getfields(t->cmd_copy, + t->cmd_words, + ARRAY_SIZE(t->cmd_words), + 1, + delim); +} + +static void +uc_cmd_tokenize_destroy(struct UCCmdTokenizer *t) + +{ + free(t->cmd_copy); + t->num_words = 0; + t->cmd_copy = NULL; +} + +void +uc_cmd_runner_init(struct UCCmdRunner *r) +{ + memset(r, 0, sizeof *r); + r->current_root = &r->_root; + r->_root.type = UC_CMD_ROOT; +} + +void +uc_cmd_node_dealloc(struct UCCmdNode *n) +{ + struct UCCmdNode *next; + + while (n) { + uc_cmd_node_dealloc(n->child); + next = n->next; + if (n->type == UC_CMD_KEYWORD) { + free(n->data.word.word); + free(n->data.word.descr); + } else if (n->type == UC_CMD_LIST) { + uc_strv_destroy(&n->data.list.words); + uc_strv_destroy(&n->data.list.descrs); + } else if (n->type == UC_CMD_STRING) { + free(n->data.word.word); + free(n->data.word.descr); + } + free(n); + n = next; + } +} + +void +uc_cmd_runner_destroy(struct UCCmdRunner *r) +{ + uc_cmd_node_dealloc(r->_root.child); + r->current_root->child = NULL; +} + +static struct UCCmdNode * +uc_cmd_node_alloc(enum UCCmdType type, uint32_t flags) +{ + struct UCCmdNode *n; + + n = calloc(1, sizeof *n); + if (n == NULL) { + return NULL; + } + + n->type = type; + n->flags = flags; + + return n; +} + +static struct +UCCmdNode *uc_cmd_node_create_list(const char *word) +{ + struct UCCmdNode *node = NULL; + + struct UCCmdTokenizer t; + + uc_cmd_tokenize(&t, word, "() |\t\v"); + if (t.num_words > 0) { + node = uc_cmd_node_alloc(UC_CMD_LIST, 0); + if (node != NULL) { + + uc_strv_init(&node->data.list.words); + uc_strv_init(&node->data.list.descrs); + + for (int i = 0; i < t.num_words; i++) { + uc_strv_append(&node->data.list.words, t.cmd_words[i]); + } + } + } + + uc_cmd_tokenize_destroy(&t); + return node; +} + +static struct UCCmdNode * +uc_cmd_node_create_word(enum UCCmdType type, const char *word) +{ + struct UCCmdNode *node; + + node = uc_cmd_node_alloc(type, 0); + if (node != NULL) { + node->data.word.word = strdup(word); + } + + return node; +} + +static struct UCCmdNode * +uc_cmd_node_create(const char *word) +{ + struct UCCmdNode *node; + + if (word[0] == '(') { //list (foo|bar|baz) + node = uc_cmd_node_create_list(word); + } else if (isupper(word[0])) { + node = uc_cmd_node_create_word(UC_CMD_STRING, word); + } else { + node = uc_cmd_node_create_word(UC_CMD_KEYWORD, word); + } + + return node; +} + +static int +uc_cmd_node_match(const struct UCCmdNode *n, const char *word, struct UCStrv *matches) +{ + size_t word_len; + int found = 0; + + if (word == NULL || word[0] == 0) { + return 0; + } + + word_len = strlen(word); + + if (n->type == UC_CMD_KEYWORD) { + + if (strncmp(word, n->data.word.word, word_len) == 0) { + if (matches != NULL) { + uc_strv_append(matches, n->data.word.word); + } + found = 1; + } + } else if (n->type == UC_CMD_LIST) { + const struct UCStrv *v = &n->data.list.words; + + assert(v); + + for(size_t i = 0; i < v->cnt; i++) { + + if (strncmp(word, v->strings[i], word_len) == 0) { + if (matches != NULL) { + uc_strv_append(matches, v->strings[i]); + } + found = 1; + } + } + } else if (n->type == UC_CMD_STRING) { + if (matches != NULL) { + uc_strv_append(matches, word); + } + found = 1; + } + + return found; + +} + +static struct UCCmdNode * +uc_cmd_add(struct UCCmdNode *parent, const char *word) +{ + struct UCCmdNode *new_node; + struct UCCmdNode **iter = &parent->child; + + assert(parent); + + new_node = uc_cmd_node_create(word); + if (new_node == NULL) { + return NULL; + } + new_node->parent = parent; + + while (*iter) { + struct UCCmdNode *n = *iter; + + if (uc_cmd_type_is_variable(new_node->type) && n->type != UC_CMD_END) { + //we don't support combinations of keywords and variables + //at the same level. + uc_cmd_node_dealloc(new_node); + return NULL; + } + //TODO check for ambiguous word (e.g. add "short" when "shorter" already exists) + if (new_node->type == UC_CMD_KEYWORD && uc_cmd_node_match(n, word, NULL)) { + uc_cmd_node_dealloc(new_node); + return *iter; + } + iter = &n->next; + } + + *iter = new_node; + + return new_node; +} + +static int +uc_cmd_node_add_help(struct UCCmdNode *node) +{ + struct UCCmdTokenizer t; + int i; + + if (node->data.cmd->help == NULL) { + //allow helpless commands + return 0; + } + + if (node->type != UC_CMD_END) { + return -10; + } + + uc_cmd_tokenize(&t, node->data.cmd->help, "\n"); + if (t.num_words <= 0) { + uc_cmd_tokenize_destroy(&t); + return -11; + } + + i = t.num_words - 1; + //we have the last node in the tree + //Walk it up towards the root(backwards) and fill + //in help texts where it's missing. + while (node->parent) { + + node = node->parent; + if (node->type == UC_CMD_ROOT) { + break; + } + + if (i < 0) { + break; + } + + if (node->type == UC_CMD_KEYWORD || + node->type == UC_CMD_STRING) { + if (node->data.word.descr == NULL && + !uc_str_empty(t.cmd_words[i])) { + node->data.word.descr = strdup(t.cmd_words[i]); + } + i--; + } else if (node->type == UC_CMD_LIST) { + if (node->data.list.descrs.cnt == 0) { + for (int k = (int)node->data.list.words.cnt -1; k >= 0; k++) { + if (i < 0) { + break; + } + uc_strv_append(&node->data.list.descrs, t.cmd_words[i]); + i--; + + } + } else { + i -= (int)node->data.list.words.cnt; + } + } + } + + uc_cmd_tokenize_destroy(&t); + + if (node->type != UC_CMD_ROOT || i != -1) { + //we didn't consume all the help tokens, so the + //command definition is screwd up + return -20; + } + + return 0; +} + +int +uc_cmd_install_noassert(struct UCCmdRunner *r, struct UCCmdDef *cmd) +{ + struct UCCmdNode *node = r->current_root; + struct UCCmdNode *new_node; + struct UCCmdTokenizer t; + int rc; + + uc_cmd_tokenize(&t, cmd->cmd, NULL); + if (t.num_words <= 0) { + uc_cmd_tokenize_destroy(&t); + return -1; + } + + for (int i = 0; i < t.num_words; i++) { + node = uc_cmd_add(node, t.cmd_words[i]); + if (node == NULL) { + uc_cmd_tokenize_destroy(&t); + return -2; + } + } + + //TODO, check for duplicate command here. + + new_node = uc_cmd_node_alloc(UC_CMD_END, 0); + if (new_node == NULL) { + uc_cmd_tokenize_destroy(&t); + return -1; + } + new_node->data.cmd = cmd; + new_node->next = node->child; + node->child = new_node; + new_node->parent = node; + + rc = uc_cmd_node_add_help(new_node); + + uc_cmd_tokenize_destroy(&t); + + return rc; +} + +void +uc_cmd_install(struct UCCmdRunner *r, struct UCCmdDef *cmd) +{ + int rc; + + rc = uc_cmd_install_noassert(r, cmd); + UC_ASSERT(rc == 0); +} + +enum UCCmdRc +uc_cmd_find(struct UCCmdNode *first, + const struct UCCmdTokenizer *t, + struct UCStrv *matches, + struct UCCmdNode **result) +{ + struct UCCmdNode *node = first; + struct UCCmdNode *found = NULL; + enum UCCmdRc rc = UC_CMDRC_NOT_FOUND; + + for (int i = 0; i < t->num_words && node; i++) { + int n_found = 0; + + while (node) { + if (uc_cmd_node_match(node, t->cmd_words[i], matches)) { + if (n_found == 0) { + //keep the 1. matched + found = node; + } + n_found++; + } + node = node->next; + } + + if (n_found == 1) { + node = found->child; + rc = UC_CMDRC_OK; + } else if (n_found > 1) { + node = found; + rc = UC_CMDRC_AMBIGUOUS; + break; + } + } + + *result = found; + + if (found == NULL) { + rc = UC_CMDRC_NOT_FOUND; + } + + return rc; +} + + +enum UCCmdRc +uc_cmd_parse_and_find(struct UCCmdRunner *r, const char *cmd_line, + struct UCStrv *matches, + struct UCCmdNode **result) +{ + + struct UCCmdNode *node = r->current_root->child; + struct UCCmdTokenizer t; + enum UCCmdRc rc = UC_CMDRC_ERROR; + + //make a copy since getfields destroys the original string + uc_cmd_tokenize(&t, cmd_line, NULL); + + if (t.num_words > 0) { + + //match the commands towards the command tree + // + rc = uc_cmd_find(node, &t, matches, result); + } + + uc_cmd_tokenize_destroy(&t); + + return rc; +} + +enum UCCmdRc +uc_cmd_help(struct UCCmdRunner *r, const char *cmd_line, struct UCStrv *completions) +{ + struct UCCmdNode *found = NULL; + enum UCCmdRc rc; + + rc = uc_cmd_parse_and_find(r, cmd_line, NULL, &found); + if (rc == UC_CMDRC_OK) { + struct UCCmdNode *node = found; + + if (node->type == UC_CMD_LIST) { + uc_strv_append_all(completions, &node->data.list.descrs, 1); + } else if (node->type == UC_CMD_STRING || + node->type == UC_CMD_KEYWORD) { + if (node->data.word.descr != NULL) { + uc_strv_append(completions, node->data.word.descr); + } + } + } + + return rc; +} + +enum UCCmdRc +uc_cmd_complete(struct UCCmdRunner *r, const char *cmd_line, struct UCStrv *completions) +{ + struct UCCmdNode *found = NULL; + enum UCCmdRc rc; + + rc = uc_cmd_parse_and_find(r, cmd_line, NULL, &found); + if (rc != UC_CMDRC_NOT_FOUND && found != NULL) { + struct UCCmdNode *node = found->child; + + while (node) { + if (node->type == UC_CMD_END) { + uc_strv_append(completions, ""); + } else if (node->type == UC_CMD_LIST) { + uc_strv_append_all(completions, &node->data.list.words, 1); + } else if (node->type == UC_CMD_STRING || + node->type == UC_CMD_KEYWORD) { + uc_strv_append(completions, node->data.word.word); + } + node = node->next; + } + } + + return rc; +} + + + +enum UCCmdRc +uc_cmd_run_ctx(struct UCCmdRunner *r, const char *cmd_line, void *ctx) +{ + struct UCCmdArgs args = { + .argv = UC_STRV_INITIALIZER, + .ctx = ctx, + }; + + struct UCCmdNode *found = NULL; + enum UCCmdRc rc; + + rc = uc_cmd_parse_and_find(r, cmd_line, &args.argv, &found); + if (rc == UC_CMDRC_OK) { + found = found->child; + // Now check the current level for any UC_CMD_END + // which indicates a complete command + while (found) { + if (found->type == UC_CMD_END) { + break; + } + found = found->next; + } + + if (found != NULL) { + const struct UCCmdDef *cmd = found->data.cmd; + args.cmd = cmd; + rc = cmd->callback(&args); + } else { + rc = UC_CMDRC_INCOMPLETE; + } + } + + uc_strv_destroy(&args.argv); + + return rc; +} + +enum UCCmdRc +uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line) +{ + return uc_cmd_run_ctx(r, cmd_line, NULL); +} + + +void print_args(const struct UCStrv *args) +{ + for (size_t i = 0; i < args->cnt; i++) { + printf("arg %zu: '%s' ", i, args->strings[i]); + } + puts(""); +} + +enum UCCmdRc cmd1_cb(const struct UCCmdArgs *args) +{ + puts(__func__); + print_args(&args->argv); + + return UC_CMDRC_OK; +} + +enum UCCmdRc cmd2_cb(const struct UCCmdArgs *args) +{ + puts(__func__); + print_args(&args->argv); + + return UC_CMDRC_OK; +} + +enum UCCmdRc cmd3_cb(const struct UCCmdArgs *args) +{ + puts(__func__); + print_args(&args->argv); + + return UC_CMDRC_OK; +} + +enum UCCmdRc cmd4_cb(const struct UCCmdArgs *args) +{ + puts(__func__); + print_args(&args->argv); + + return UC_CMDRC_OK; +} + +void do_complete(struct UCCmdRunner *r, const char *command) +{ + struct UCStrv completions = UC_STRV_INITIALIZER; + + uc_cmd_complete(r, command, &completions); + if (completions.cnt > 0) { + printf("Possible completions for '%s' :\n", command); + for (size_t i = 0; i < completions.cnt; i++) { + printf("\t%s\n", completions.strings[i]); + } + } else { + printf("No completions for '%s' :\n", command); + } + + uc_strv_destroy(&completions); +} + +void do_help(struct UCCmdRunner *r, const char *command) +{ + struct UCStrv completions = UC_STRV_INITIALIZER; + + uc_cmd_help(r, command, &completions); + if (completions.cnt > 0) { + printf("help for '%s' :\n", command); + for (size_t i = 0; i < completions.cnt; i++) { + printf("\t%s\n", completions.strings[i]); + } + } else { + printf("No help for '%s' :\n", command); + } + + uc_strv_destroy(&completions); +} + + +int main(int argc, char *argv[]) +{ + char line[128]; + struct UCCmdRunner r; + struct UCCmdDef cmd1 = { + "show all", + "show stuff\nEverything\n", + cmd1_cb, + 0, + NULL + }; + + struct UCCmdDef cmd2 = { + "show empty", + " \n everyhing that's empty\n", + cmd2_cb, + 0, + NULL + }; + + struct UCCmdDef cmd3 = { + "show empty bottle", + NULL, + cmd3_cb, + 0, + NULL + }; + + struct UCCmdDef cmd4 = { + "delete file NAME", + "delete\nfile\nName of the file\n", + cmd4_cb, + 0, + NULL + }; + + uc_cmd_runner_init(&r); + uc_cmd_install(&r, &cmd1); + uc_cmd_install(&r, &cmd2); + uc_cmd_install(&r, &cmd3); + uc_cmd_install(&r, &cmd4); + + uc_cmd_run(&r, "delete file /tmp/a"); + uc_cmd_run(&r, "show all"); + uc_cmd_run(&r, "show empty"); + uc_cmd_run(&r, "sh emp b"); + uc_cmd_run(&r, ""); + + do_help(&r, "delete file /tmp/a"); + do_help(&r, "show empty"); + do_help(&r, "show all"); + do_help(&r, "sh"); + do_help(&r, ""); + /* + while (fgets(line,sizeof line, stdin)) { + enum UCCmdRc rc = uc_cmd_run(&r, line); + if (rc != UC_CMDRC_OK) { + printf("Command failed with code %d\n", rc); + } + } + */ + + do_complete(&r, "sho em"); + do_complete(&r, "show "); + do_complete(&r, ""); + do_complete(&r, "delet "); + do_complete(&r, "delete "); + do_complete(&r, "delete file"); + do_complete(&r, "delete fil"); + uc_cmd_runner_destroy(&r); + + + return 1; +} diff --git a/src/getfields.c b/src/getfields.c index 504ffdb..091232e 100644 --- a/src/getfields.c +++ b/src/getfields.c @@ -2,7 +2,7 @@ #include "ucore/string.h" int -getfields(char *str, char **args, int max, int mflag, const char *set) +uc_getfields(char *str, char **args, int max, int mflag, const char *set) { char r; int intok, narg; diff --git a/src/gettokens.c b/src/gettokens.c new file mode 100644 index 0000000..967463e --- /dev/null +++ b/src/gettokens.c @@ -0,0 +1,58 @@ +#include +#include "ucore/string.h" + +//tokenize string, and exclude the quotes +static char *qtoken(char *s, const char *sep) +{ + int inquote = 0; + char *t = s; + while (*t != 0 && (inquote || strchr(sep, *t) == NULL)) { + if (*t != '"') { + *s++ = *t++; + continue; + } + + if (!inquote) { + inquote = 1; + t++; + continue; + } + + if (t[1] != '"') { + t++; + inquote = 0; + continue; + } + //double quotes, merged to 1 quote + t++; + *s++ = *t++; + } + + if (*s != 0) { + *s = 0; + if (t == s) { + t++; + } + } + + return t; +} + +int uc_gettokens(char *str, char **args, int maxargs, const char *sep) +{ + int nargs; + + for (nargs = 0; nargs < maxargs; nargs++) { + while (*str != 0 && strchr(sep, *str) != NULL) { + *str++ = 0; + } + if (*str == 0) { + break; + } + args[nargs] = str; + str = qtoken(str, sep); + } + + return nargs; +} + diff --git a/src/iomux_impl.c b/src/iomux_impl.c index 7b318b9..12c62a3 100644 --- a/src/iomux_impl.c +++ b/src/iomux_impl.c @@ -151,7 +151,6 @@ int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd, unsigned int what if (fd->what != what) { fd->what = what; rc = mux->ops.update_events_impl(mux, fd); - fd->what = what; } return rc; diff --git a/src/iomux_select.c b/src/iomux_select.c index 488450b..9f71773 100644 --- a/src/iomux_select.c +++ b/src/iomux_select.c @@ -44,7 +44,7 @@ static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd) struct IOMuxSelect *mux = mux_->instance; if (fd->fd < 0 || fd->fd >= FD_SETSIZE) { - return EINVAL; + return ENFILE; } if (fd->what & MUX_EV_READ) @@ -70,7 +70,7 @@ static int iomux_select_register_fd(struct IOMux *mux_, struct IOMuxFD *fd) rc = iomux_select_update_events(mux_, fd); if (rc != 0) { - return ENFILE; + return rc; } mux->descriptors[fd->fd] = fd; diff --git a/src/mersenne_twister.c b/src/mersenne_twister.c index 201a3cf..d79e8f0 100644 --- a/src/mersenne_twister.c +++ b/src/mersenne_twister.c @@ -1,4 +1,4 @@ -/*Copyright (c) 2004 Nils O. Selåsdal */ +/*Copyright (c) 2004 Nils O. Sel�sdal */ /*Straight forward attempt at a Mersenne Twister PRNG */ #include "ucore/mersenne_twister.h" @@ -24,7 +24,7 @@ enum { void mtsrand(int seed, MTRand *r) { - int j; + unsigned j; for (j = 0 ; j < N ; j++) { r->x[j] = seed * ((j+1)<< 3)|0x1; } @@ -36,16 +36,16 @@ 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; @@ -55,7 +55,7 @@ unsigned int mtrand(MTRand *r) r->i = (r->i + 1) % N; return y; -} +} #ifdef TEST_MT #include #include diff --git a/src/slot_allocator.c b/src/slot_allocator.c new file mode 100644 index 0000000..cd5fd0a --- /dev/null +++ b/src/slot_allocator.c @@ -0,0 +1,67 @@ + +#include +#include +#include +#include "ucore/bitvec.h" +#include "ucore/slot_allocator.h" + +void *uc_slot_alloc(UCSlotAlloc *sa) +{ + int free_slot = uc_bv_find_first_zero(&sa->bitmap); + if (free_slot < 0) { + return NULL; + } else if ((size_t)free_slot >= sa->num_slots) { // bit vector may have more bits than slots + return NULL; + } + + uc_bv_set_bit(&sa->bitmap, free_slot); + + return sa->slots + free_slot * sa->slot_size; +} + +void uc_slot_free(UCSlotAlloc *restrict sa, void *restrict slot) +{ + assert((uint8_t *)slot >= sa->slots); + int slot_index = ((uint8_t *)slot - sa->slots) / sa->slot_size; + assert((size_t)slot_index < sa->num_slots); + uc_bv_clr_bit(&sa->bitmap, slot_index); +} + +int main() +{ + + UC_SLOT_ALLOC_DEF(sa, 24, 1) + + void *p1 = uc_slot_alloc(&sa); + printf("%p\n", &sa_memory.memory[0]); + printf("%p\n", p1); + + void *p2 = uc_slot_alloc(&sa); + printf("%p\n", p2); + uc_slot_free(&sa, p1); + + p2 = uc_slot_alloc(&sa); + printf("%p\n", p2); + + printf("__malloc__\n"); + void *v = malloc(24 * (1<<16)); + UC_SLOT_ALLOC_DEF_EX(sa2, 24, (1<<16), v) + char *v2 = NULL; + for (int i = 0; i < 1<<16; i++) { + char *c = uc_slot_alloc(&sa2); + if (c == NULL) { + printf("uc_slot_alloc failed at %d\n", i); + break; + } + *c = i; + if (i == 0) { + v2 = c; + } + } + for (int i = (1<<16) -1 ; i >= 0; i--) { + uc_slot_free(&sa2, v2 + 24*i); + } + free(v); + return 0; +} + diff --git a/src/strvec.c b/src/strvec.c index 1e9f00a..3ed3d8e 100644 --- a/src/strvec.c +++ b/src/strvec.c @@ -130,3 +130,14 @@ int uc_strv_append_all(struct UCStrv *restrict a, struct UCStrv *restrict b, int return 0; } +void uc_strv_reverse(struct UCStrv *strv) +{ + for (size_t i = 0; i < strv->cnt / 2; i++) { + + size_t k = strv->cnt - i - 1; + char *tmp = strv->strings[i]; + + strv->strings[i] = strv->strings[k]; + strv->strings[k] = tmp; + } +} diff --git a/src/version.c.in b/src/version.c.in index ade8110..fe80391 100644 --- a/src/version.c.in +++ b/src/version.c.in @@ -1,11 +1,11 @@ //Various info about the version and build. //The SConscript file substitutes these at build time -const int ucore_version_major = @version_major@; -const int ucore_version_minor = @version_minor@; -const int ucore_version_patch = @version_patch@; +const int ucore_version_major = @libucore_VERSION_MAJOR@; +const int ucore_version_minor = @libucore_VERSION_MINOR@; +const int ucore_version_patch = @libucore_VERSION_PATCH@; -const char ucore_version_str[] = "@version_str@"; +const char ucore_version_str[] = "@libucore_VERSION@"; const char ucore_build_host[] = "@build_host@"; const char ucore_build_type[] = "@build_type@"; diff --git a/src/wqueue.c b/src/wqueue.c index 5526d78..47752ce 100644 --- a/src/wqueue.c +++ b/src/wqueue.c @@ -15,7 +15,7 @@ static int uc_wqueue_handle_write(struct UCWQueue *wqueue) q = UC_TAILQ_FIRST(&wqueue->queue); mbuf = UC_TAILQ_CONTAINER(q, struct MBuf, entry); - rc = wqueue->write_cb(mux, fd, mbuf); + rc = wqueue->write_cb(mux, wqueue, mbuf); if (rc <= 0) { //NOTE for rc < 0, nothing can touch the wqueue or fd //any more, as it might been free'd @@ -24,7 +24,7 @@ static int uc_wqueue_handle_write(struct UCWQueue *wqueue) mbuf = uc_mbuf_dequeue(&wqueue->queue); assert(mbuf != NULL); - uc_mbuf_free(mbuf); + wqueue->free_cb(mbuf); wqueue->queue_len--; } @@ -58,7 +58,7 @@ static void uc_wqueue_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int wha if (rc >= 0 && what & MUX_EV_READ) { - rc = wqueue->read_cb(mux, fd); + rc = wqueue->read_cb(mux, wqueue); //NOTE - can't touch the wqueue or fd after this point, //as it might been free'd } @@ -71,7 +71,7 @@ void uc_wqueue_init(struct UCWQueue *wqueue, struct IOMux *mux) memset(wqueue, 0, sizeof *wqueue); wqueue->mux = mux; wqueue->fd.callback = uc_wqueue_cb; - + wqueue->free_cb = uc_mbuf_free; uc_tailq_init(&wqueue->queue); } @@ -81,7 +81,7 @@ int uc_wqueue_clear(struct UCWQueue *wqueue) int rc = 0; while ((buf = uc_mbuf_dequeue(&wqueue->queue)) != NULL) { - uc_mbuf_free(buf); + wqueue->free_cb(buf); wqueue->queue_len--; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..6e9f79b --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,16 @@ +file(GLOB TEST_SOURCE_FILES test_*.c) + +link_libraries(check ucore Threads::Threads) +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + include_directories("/opt/homebrew/include") + link_directories("/opt/homebrew/lib") + list(REMOVE_ITEM TEST_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/test_ringbuf.c) +else() + link_libraries(rt) +endif() + +add_executable(test_runner ${TEST_SOURCE_FILES}) + +add_custom_target(test COMMAND test_runner + DEPENDS test_runner + WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}) diff --git a/test/SConscript b/test/SConscript index 7c40727..37b6141 100644 --- a/test/SConscript +++ b/test/SConscript @@ -39,4 +39,4 @@ cmd = test_env.Command(target='test_phony' , action= test_env.Dir('.').abspath + '/' + test_executable) test_env.Depends(cmd, prog) test_env.AlwaysBuild(cmd) - +test_env.Default(test_executable) diff --git a/test/console_print.c b/test/console_print.c index a22d562..3e15e99 100644 --- a/test/console_print.c +++ b/test/console_print.c @@ -9,7 +9,7 @@ #include -int stdout_read(struct IOMux *mux, struct IOMuxFD *fd) +int stdout_read(struct IOMux *mux, struct UCWQueue *wqueue) { return 1; } @@ -24,9 +24,9 @@ void stdin_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) printf("Read %d bytes\n", len); if (len <= 0) { uc_mbuf_free(mbuf); - iomux_unregister_fd(mux, fd); - uc_wqueue_clear(wqueue); iomux_unregister_fd(mux, &wqueue->fd); + uc_wqueue_clear(wqueue); + iomux_unregister_fd(mux, fd); return; } @@ -44,7 +44,7 @@ struct IOMuxFD stdin_fd = { }; -int stdout_write(struct IOMux *mux, struct IOMuxFD *fd, struct MBuf *mbuf) +int stdout_write(struct IOMux *mux, struct UCWQueue *wqueue, struct MBuf *mbuf) { uint32_t len; ssize_t wlen; @@ -52,7 +52,7 @@ int stdout_write(struct IOMux *mux, struct IOMuxFD *fd, struct MBuf *mbuf) len = uc_mbuf_len(mbuf); data = uc_mbuf_pull(mbuf, len); - wlen = write(fd->fd, data, len); + wlen = write(wqueue->fd.fd, data, len); if (wlen < 0) { if (errno != EWOULDBLOCK) { diff --git a/test/iomux_pipe_close.c b/test/iomux_pipe_close.c new file mode 100644 index 0000000..11590e2 --- /dev/null +++ b/test/iomux_pipe_close.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include +#include "ucore/iomux.h" + + + +void in_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) +{ + + char buf[16]; + ssize_t rc; + + rc = read(fd->fd, buf, sizeof buf); + printf("Read returned %ld\n", (long)rc); + if (rc <= 0) { + if (rc == -1 && errno == EAGAIN) { + return; + } else if (rc == -1) { + perror("read"); + } + return; + } + iomux_unregister_fd(mux, fd); + close(fd->fd); + +} + +void out_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) +{ + char str[] = "hello"; + ssize_t rc; + + rc = write(fd->fd, str, strlen(str)); + printf("write returned %ld\n", (long)rc); + if (rc <= 0) { + if (rc == -1 && errno == EAGAIN) { + return; + } else { + perror("write"); + } + iomux_unregister_fd(mux, fd); + } +} + + +int main(int argc, char *argv[]) +{ + int pipes[2]; + pipe(pipes); + uc_set_nonblocking(pipes[0]); + uc_set_nonblocking(pipes[1]); + + struct IOMuxFD rfd= { + .fd = pipes[0], + .what = MUX_EV_READ, + .callback = in_cb, + }; + + struct IOMuxFD wfd= { + .fd = pipes[1], + .what = MUX_EV_WRITE, + .callback = out_cb, + }; + + signal(SIGPIPE, SIG_IGN); + + struct IOMux *mux = iomux_create(IOMUX_TYPE_SELECT); + iomux_register_fd(mux, &rfd); + iomux_register_fd(mux, &wfd); + + iomux_run(mux); + + return 0; +} + diff --git a/test/test_bcd.c b/test/test_bcd.c index 65732b1..43b9f93 100644 --- a/test/test_bcd.c +++ b/test/test_bcd.c @@ -8,12 +8,12 @@ START_TEST (test_2bcd_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]); + ck_assert_int_eq(len, 5); + ck_assert_int_eq(bcd[0], 0x21); + ck_assert_int_eq(bcd[1], 0x43); + ck_assert_int_eq(bcd[2], 0x65); + ck_assert_int_eq(bcd[3], 0x87); + ck_assert_int_eq(bcd[4], 0x09); } END_TEST @@ -23,7 +23,7 @@ START_TEST (test_2bcd_empty) unsigned char bcd[1]; size_t len = uc_ascii2bcd(ascii, bcd, 3); - fail_if(len != 0, "len is %zu", len); + ck_assert_int_eq(len, 0); } END_TEST @@ -33,8 +33,8 @@ START_TEST (test_2bcd_1_filler) 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]); + ck_assert_int_eq(len, 1); + ck_assert_int_ne(bcd[0], 0); } END_TEST @@ -44,10 +44,10 @@ START_TEST (test_2bcd_2_filler) 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]); - fail_if(UC_BCD_LEN(strlen(ascii)) != len); + ck_assert_int_eq(len , 2); + ck_assert_int_eq(bcd[0] , 0x21); + ck_assert_int_eq(bcd[1] , 0xf3); + ck_assert_int_eq(UC_BCD_LEN(strlen(ascii)) , len); } END_TEST @@ -58,9 +58,9 @@ START_TEST (test_2bcd_3_filler) 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]); + ck_assert_int_eq(len , 2); + ck_assert_int_eq(bcd[0] , 0x21); + ck_assert_int_eq(bcd[1] , 0x03); } END_TEST @@ -71,7 +71,7 @@ START_TEST (test_2bcd_non_digits) unsigned char bcd[10]; size_t len = uc_ascii2bcd(ascii, bcd, 0x0); - fail_if(len != 0, "len is %zu", len); + ck_assert_int_eq(len , 0); } END_TEST @@ -82,12 +82,12 @@ START_TEST (test_2bcd_phoneno) 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]); + ck_assert_int_eq(len , 5); + ck_assert_int_eq(bcd[0] , 0x00); + ck_assert_int_eq(bcd[1] , 0x74); + ck_assert_int_eq(bcd[2] , 0x23); + ck_assert_int_eq(bcd[3] , 0x33); + ck_assert_int_eq(bcd[4] , 0xf4); } END_TEST @@ -98,8 +98,8 @@ START_TEST (test_2bcd_binary) 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]); + ck_assert_int_eq(len , 1); + ck_assert_int_eq(bcd[0], 0xf2); } END_TEST @@ -110,13 +110,13 @@ START_TEST (test_2hex_1) 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]); - fail_if(UC_ASCII_LEN(sizeof bcd) != len); + ck_assert_int_eq(len, 4); + ck_assert_int_eq(ascii[0], '1'); + ck_assert_int_eq(ascii[1], '2'); + ck_assert_int_eq(ascii[2], '3'); + ck_assert_int_eq(ascii[3], '4'); + ck_assert_int_eq(ascii[4], 0); + ck_assert_int_eq(UC_ASCII_LEN(sizeof bcd) , len); } END_TEST @@ -127,14 +127,14 @@ START_TEST (test_2hex_2) 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]); + ck_assert_int_eq(len , 6); + ck_assert_int_eq(ascii[0] , '0'); + ck_assert_int_eq(ascii[1] , 'F'); + ck_assert_int_eq(ascii[2] , 'F'); + ck_assert_int_eq(ascii[3] , 'F'); + ck_assert_int_eq(ascii[4] , '0'); + ck_assert_int_eq(ascii[5] , '0'); + ck_assert_int_eq(ascii[6] , 0); } END_TEST @@ -146,8 +146,8 @@ START_TEST (test_2hex_empty) 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]); + ck_assert_int_eq(len, 0); + ck_assert_int_eq(ascii[0], 0); } END_TEST diff --git a/test/test_bitvec.c b/test/test_bitvec.c index 11fe28e..a3ec81c 100644 --- a/test/test_bitvec.c +++ b/test/test_bitvec.c @@ -9,7 +9,7 @@ START_TEST (test_bitvec_1) size_t i; for (i = 0; i < sizeof s * 8; i++) - fail_if(uc_bv_get_bit(&v, i), "bit %zu is not 0", i); + ck_assert_int_eq(uc_bv_get_bit(&v, i), 0); } END_TEST @@ -23,7 +23,7 @@ START_TEST (test_bitvec_2) uc_bv_set_bit(&v, i); for (i = 0; i < sizeof s * 8; i++) - fail_if(uc_bv_get_bit(&v, i) != 1 , "bit %zu is not 1", i); + ck_assert_int_eq(uc_bv_get_bit(&v, i), 1); } END_TEST @@ -34,13 +34,13 @@ START_TEST (test_bitvec_clearbit) size_t i; for (i = 0; i < sizeof(uc_bv_integer) * 8; i++) - fail_if(uc_bv_get_bit(&v, i) != 1 , "bit %zu is not 1", i); + ck_assert_int_eq(uc_bv_get_bit(&v, i), 1); for (i = 0; i < sizeof(uc_bv_integer) * 8; i++) uc_bv_clr_bit(&v, i); for (i = 0; i < sizeof(uc_bv_integer) * 8; i++) - fail_if(uc_bv_get_bit(&v, i) != 0 , "bit %zu is not 0", i); + ck_assert_int_eq(uc_bv_get_bit(&v, i), 0); } END_TEST @@ -48,14 +48,14 @@ END_TEST START_TEST (test_bitvec_set_bits_from_array) { struct UCBitVec *v = uc_bv_new(5); - char a[] = {1, 0,1 ,0, 1}; + char a[] = {1, 0, 1 ,0, 1}; uc_bv_set_bits_from_array(v,a , 5); - fail_if(uc_bv_get_bit(v, 0) != 1 , "bit 0 is wrong"); - fail_if(uc_bv_get_bit(v, 1) != 0 , "bit 1 is wrong"); - fail_if(uc_bv_get_bit(v, 2) != 1 , "bit 2 is wrong"); - fail_if(uc_bv_get_bit(v, 3) != 0 , "bit 3 is wrong"); - fail_if(uc_bv_get_bit(v, 4) != 1 , "bit 4 is wrong"); + ck_assert_int_eq(uc_bv_get_bit(v, 0), 1); + ck_assert_int_eq(uc_bv_get_bit(v, 1), 0); + ck_assert_int_eq(uc_bv_get_bit(v, 2), 1); + ck_assert_int_eq(uc_bv_get_bit(v, 3), 0); + ck_assert_int_eq(uc_bv_get_bit(v, 4), 1); uc_bv_free(v); } @@ -70,15 +70,40 @@ START_TEST (test_bitvec_setall_clearall) uc_bv_set_all(v); for (i = 0; i < 511; i++) - fail_if(uc_bv_get_bit(v, i) != 1 , "bit %zu is not 1", i); + ck_assert_int_eq(uc_bv_get_bit(v, i), 1); uc_bv_clr_all(v); for (i = 0; i < sizeof(uc_bv_integer) * 8; i++) - fail_if(uc_bv_get_bit(v, i) != 0 , "bit %zu is not 0", i); + ck_assert_int_eq(uc_bv_get_bit(v, i), 0); uc_bv_free(v); +} +END_TEST +START_TEST (test_bitvec_find_first_zero) +{ + uc_bv_integer buf[8]; + struct UCBitVec v = UC_BV_STATIC_INIT(buf); + uc_bv_set_all(&v); + + int bit = uc_bv_find_first_zero(&v); + ck_assert_int_eq(bit, -1); + + uc_bv_clr_bit(&v, 0); + bit = uc_bv_find_first_zero(&v); + ck_assert_int_eq(bit, 0); + + uc_bv_set_bit(&v, 0); + uc_bv_clr_bit(&v, 63); + bit = uc_bv_find_first_zero(&v); + ck_assert_int_eq(bit, 63); + + uc_bv_set_bit(&v, 63); + uc_bv_clr_bit(&v, sizeof buf * CHAR_BIT - 1); + bit = uc_bv_find_first_zero(&v); + ck_assert_int_eq(bit, sizeof buf * CHAR_BIT - 1); + } END_TEST @@ -91,6 +116,8 @@ Suite *bitvec_suite(void) 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); + tcase_add_test(tc, test_bitvec_find_first_zero); + suite_add_tcase(s, tc); return s; diff --git a/test/test_buffer.c b/test/test_buffer.c index 3f09ad4..8d8cfec 100644 --- a/test/test_buffer.c +++ b/test/test_buffer.c @@ -60,8 +60,8 @@ START_TEST (test_gbuf_printf1) fail_if(buf == NULL); rc = uc_gbuf_printf(buf, "test %d", 1); - fail_if(rc != 6, "rc was %d", rc); - fail_if(buf->used != 6, "buf->used was %d", buf->used); + fail_if(rc != 6); + fail_if(buf->used != 6); fail_if(strcmp("test 1", buf->buf) != 0); uc_gbuf_unref(buf); @@ -76,8 +76,8 @@ START_TEST (test_gbuf_printf2) fail_if(buf == NULL); rc = uc_gbuf_printf(buf, "test %d test %d test %d", 1, 2, 3); - fail_if(rc != 20, "rc was %d", rc); - fail_if(buf->used != 20, "buf->used was %d", buf->used); + fail_if(rc != 20); + fail_if(buf->used != 20); fail_if(strcmp("test 1 test 2 test 3", buf->buf) != 0); uc_gbuf_unref(buf); @@ -92,14 +92,14 @@ START_TEST (test_gbuf_printf3) fail_if(buf == NULL); rc = uc_gbuf_printf(buf, "test %d test %d test %d", 1, 2, 3); - fail_if(rc != 20, "rc was %d", rc); - fail_if(buf->used != 20, "buf->used was %d", buf->used); + fail_if(rc != 20); + fail_if(buf->used != 20); fail_if(strcmp("test 1 test 2 test 3", buf->buf) != 0); rc = uc_gbuf_printf(buf, " test %d test %d", 4, 5); - fail_if(rc != 14, "rc was %d", rc); - fail_if(buf->used != 34, "buf->used was %d", buf->used); + fail_if(rc != 14); + fail_if(buf->used != 34); fail_if(strcmp("test 1 test 2 test 3 test 4 test 5", buf->buf) != 0); uc_gbuf_unref(buf); @@ -110,11 +110,10 @@ START_TEST (test_gbuf_printf_empty_string) { int rc; GBuf *buf = uc_new_gbuf(1); - const char *fmt = ""; //tricks gcc to not warn about empty format string fail_if(buf == NULL); - rc = uc_gbuf_printf(buf, fmt); + rc = uc_gbuf_printf(buf, ""); fail_if(rc != 0); fail_if(buf->used != 0); uc_gbuf_unref(buf); diff --git a/test/test_dbuf.c b/test/test_dbuf.c index 2b63aa5..8714812 100644 --- a/test/test_dbuf.c +++ b/test/test_dbuf.c @@ -33,7 +33,7 @@ START_TEST (test_dbuf) fail_if(uc_dbuf_remaining(&buf) != 105); fail_if(uc_dbuf_len(&buf) != 5); ck_assert_str_eq((char *)buf.start, "ABCD"); - + uc_dbuf_take(&buf, 5); fail_if(uc_dbuf_remaining(&buf) != 120); @@ -154,7 +154,7 @@ START_TEST (test_dbuf_add_ensure_take) fail_if(rc != 0); //ok, dbuf adds the ensured capacity to the existing buflen //so it becomes 100, not 90 even though the buffer is already empty - fail_if(uc_dbuf_remaining(buf) != 100, "remaining %zu", (uc_dbuf_remaining(buf))); + fail_if(uc_dbuf_remaining(buf) != 100); fail_if(uc_dbuf_buflen(buf) != 100); memset(buf->end, 0xDE, 90); uc_dbuf_added(buf, 90); diff --git a/test/test_hex.c b/test/test_hex.c index 03b6982..c0aad28 100644 --- a/test/test_hex.c +++ b/test/test_hex.c @@ -22,7 +22,7 @@ START_TEST (test_uc_hex_encode_2) uc_hex_encode(binary, sizeof binary, hex); - fail_if(strcmp(hex,"7F8081") != 0, "was %s", hex); + fail_if(strcmp(hex,"7F8081") != 0); } END_TEST @@ -34,7 +34,7 @@ START_TEST (test_uc_hex_encode_3) uc_hex_encode(binary, sizeof binary, hex); - fail_if(strcmp(hex,"0001090B") != 0, "was %s", hex); + fail_if(strcmp(hex,"0001090B") != 0); } END_TEST @@ -62,7 +62,7 @@ START_TEST (test_uc_hex_decode_1) fail_if(binary[0] != 0x1f); fail_if(binary[1] != 0x22); - fail_if(res != binary + 1, "binary %p, res %p", &binary[0], res); + fail_if(res != binary + 1); } END_TEST @@ -78,7 +78,7 @@ START_TEST (test_uc_hex_decode_2) 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); + fail_if(res != binary + 3); } END_TEST @@ -110,7 +110,7 @@ START_TEST (test_uc_hex_decode_empty_string) fail_if(binary[0] != 0x11); fail_if(binary[1] != 0x11); fail_if(binary[2] != 0x11); - fail_if(res != binary, "length %zu\n", res - binary); + fail_if(res != binary); } END_TEST @@ -125,7 +125,7 @@ START_TEST (test_uc_hex_decode_spaces) fail_if(binary[0] != 0x11); fail_if(binary[1] != 0x12); fail_if(binary[2] != 0x13); - fail_if(res != binary+3, "length %zu\n", res - binary); + fail_if(res != binary+3); } END_TEST @@ -141,7 +141,7 @@ START_TEST (test_uc_hex_decode_spaces2) fail_if(binary[0] != 0x11); fail_if(binary[1] != 0x12); fail_if(binary[2] != 0x13); - fail_if(res != binary+3, "length %zu\n", res - binary); + fail_if(res != binary+3); } END_TEST @@ -156,7 +156,7 @@ START_TEST (test_uc_hex_decode_spaces_empty) fail_if(binary[0] != 0x11); fail_if(binary[1] != 0x12); - fail_if(res != binary, "length %zu\n", res - binary); + fail_if(res != binary); } END_TEST @@ -201,7 +201,7 @@ START_TEST (test_uc_hex_encode_delim_1) 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(strcmp(hex, "FF 00 7F 0A ") != 0); *res = 0; fail_if(res != hex + 12); @@ -216,8 +216,8 @@ START_TEST (test_uc_hex_encode_delim_2) 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 + 7, "sz was %zu", res - hex); + fail_if(strcmp(hex, "FF \n00 ") != 0); + fail_if(res != hex + 7); } END_TEST @@ -230,7 +230,7 @@ START_TEST (test_uc_hex_encode_delim_zero_len) res = uc_hex_encode_delim(binary, 0, hex, sizeof hex, " \n"); - fail_if(strcmp(hex, "") != 0, "hex was '%s'", hex); + fail_if(strcmp(hex, "") != 0); fail_if(res != hex); } @@ -247,7 +247,7 @@ START_TEST (test_uc_hex_decode_lowercase) fail_if(binary[0] != 0x1f); fail_if(binary[1] != 0x22); - fail_if(res != binary + 1, "binary %p, res %p", &binary[0], res); + fail_if(res != binary + 1); } END_TEST @@ -263,7 +263,7 @@ Suite *hex_suite(void) 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); diff --git a/test/test_logging.c b/test/test_logging.c index 126c90a..a6c1667 100644 --- a/test/test_logging.c +++ b/test/test_logging.c @@ -10,7 +10,7 @@ #define FILE_NAME "logfile_test.log" #define SUBDIR "log_subdir" #define SUBDIR_FILE_NAME SUBDIR "/" FILE_NAME -//Note that these tests are comewhat fragile as they depend on the +//Note that these tests are comewhat fragile as they depend on the //file sizes that are created, which depends on the (relative)paths of this file. //for cleaning the created log files.. static void logging_rm_files(void) @@ -61,8 +61,7 @@ START_TEST (test_logfile_location) UC_LOGF(UC_LL_ERROR, 0, "Lorum ipson 5"); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 380, "was %ld", (long)st.st_size); + fail_if(rc != 0); } END_TEST @@ -85,7 +84,7 @@ START_TEST (test_logfile_delete_destination) uc_log_init(&mods); - dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1); + dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 0); fail_if(dest == NULL); uc_log_add_destination(dest); uc_log_add_destination(dest); //adding this twice should do nothing @@ -97,8 +96,8 @@ START_TEST (test_logfile_delete_destination) UC_LOGF(UC_LL_ERROR, 0, "Lorum ipson 5"); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 380, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 260); uc_log_delete_destination(dest); @@ -110,8 +109,8 @@ START_TEST (test_logfile_delete_destination) //since we deleted destinatiion, no more logging should appear in the file rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 380, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 260); } END_TEST @@ -143,8 +142,8 @@ START_TEST (test_logfile_no_location) UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 52*2, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 52*2); } END_TEST @@ -169,16 +168,16 @@ START_TEST (test_logfile_loglevel_surpressed_dest) //file destination have UC_LL_WARNING, so nothing should be logged - dest = uc_log_new_file(FILE_NAME, UC_LL_WARNING, 10); + dest = uc_log_new_file(FILE_NAME, UC_LL_WARNING, 10); fail_if(dest == NULL); uc_log_add_destination(dest); UC_LOGF(UC_LL_INFO, 1, "Lorum ipson %d", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); + fail_if(rc != 0); - fail_if(st.st_size != 0, "was %ld", (long)st.st_size); + fail_if(st.st_size != 0); } END_TEST @@ -203,16 +202,16 @@ START_TEST (test_logfile_loglevel_surpressed_module) uc_log_init(&mods); - dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1); + dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1); fail_if(dest == NULL); uc_log_add_destination(dest); UC_LOGF(UC_LL_INFO, 0, "Lorum ipson %d", 100); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); + fail_if(rc != 0); - fail_if(st.st_size != 0, "was %ld", (long)st.st_size); + fail_if(st.st_size != 0); } END_TEST @@ -235,7 +234,7 @@ START_TEST (test_logfile_reopen_files) uc_log_init(&mods); - dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1); + dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 0); fail_if(dest == NULL); uc_log_add_destination(dest); @@ -243,20 +242,20 @@ START_TEST (test_logfile_reopen_files) UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 77*2, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 104); rc = remove(FILE_NAME); - fail_if(rc != 0, "Remove failed %s", strerror(errno)); - + fail_if(rc != 0); + rc = uc_log_reopen_files(); - fail_if(rc != 0, "uc_log_reopen_files failed: %d", rc); + fail_if(rc != 0); UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "2. stat failed: %s", strerror(errno)); - fail_if(st.st_size != 77, "was %ld", (long)st.st_size);//should only one line there now + fail_if(rc != 0); + fail_if(st.st_size != 52);//should only one line there now } END_TEST @@ -281,10 +280,10 @@ START_TEST (test_logfile_remove_dest) uc_log_init(&mods); - dest1 = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1); + dest1 = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 0); fail_if(dest1 == NULL); - dest2 = uc_log_new_stderr(UC_LL_WARNING, 1); + dest2 = uc_log_new_stderr(UC_LL_WARNING, 0); fail_if(dest2 == NULL); uc_log_add_destination(dest1); @@ -294,25 +293,25 @@ START_TEST (test_logfile_remove_dest) UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 77*2, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 104); uc_log_remove_destination(dest1); UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); //should not be logged now rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "2. stat failed: %s", strerror(errno)); - fail_if(st.st_size != 77*2, "was %ld", (long)st.st_size);//should be same size + fail_if(rc != 0); + fail_if(st.st_size != 104);//should be same size //removing the last destination should be fine too uc_log_remove_destination(dest2); - UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); + UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "2. stat failed: %s", strerror(errno)); - fail_if(st.st_size != 77*2, "was %ld", (long)st.st_size);//should be same size + fail_if(rc != 0); + fail_if(st.st_size != 104);//should be same size } END_TEST @@ -337,7 +336,7 @@ START_TEST (test_logfile_full_filesystem) uc_log_init(&mods); dest = uc_log_new_file("/dev/full", UC_LL_DEBUG, 1); - fail_if(dest == NULL, "Cannot open /dev/full"); + fail_if(dest == NULL); uc_log_add_destination(dest); for (i = 0; i < 1024; i++) { @@ -397,7 +396,7 @@ START_TEST (test_logfile_invalid_file_after_reopen) logging_rm_subdir(); rc = access(SUBDIR_FILE_NAME, W_OK); - fail_if(rc == 0, "Test setup is wrong. Can still access" SUBDIR_FILE_NAME ""); + fail_if(rc == 0); UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); UC_LOGF(UC_LL_WARNING, 0, "Lorum ipson %d", 1); @@ -440,8 +439,8 @@ START_TEST (test_logfile_raw) UC_LOGFR(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 14*2, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 14*2); } END_TEST @@ -480,16 +479,16 @@ START_TEST (test_logfile_dest_mask) UC_LOGFR(UC_LL_DEBUG, 0, "Lorum ipson %d", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 0, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 0); uc_log_destination_set_mask(dest, "MOD1=DEBUG:mod2=Debug"); UC_LOGFR(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1); UC_LOGFR(UC_LL_DEBUG, 1, "Lorum ipson %d\n", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 14*2, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 14*2); } END_TEST @@ -519,8 +518,8 @@ START_TEST (test_loglevel_module_none) UC_LOGFR(UC_LL_ERROR, 0, "Lorum ipson %d\n", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 0, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 0); } END_TEST @@ -550,8 +549,8 @@ START_TEST (test_loglevel_dest_none) UC_LOGFR(UC_LL_WARNING, 0, "Lorum ipson %d\n", 1); rc = stat(FILE_NAME, &st); - fail_if(rc != 0, "stat failed: %s", strerror(errno)); - fail_if(st.st_size != 0, "was %ld", (long)st.st_size); + fail_if(rc != 0); + fail_if(st.st_size != 0); } END_TEST diff --git a/test/test_pack.c b/test/test_pack.c index 522b67e..19308af 100644 --- a/test/test_pack.c +++ b/test/test_pack.c @@ -9,8 +9,8 @@ START_TEST (test_pack16_le_1) 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]); + fail_if(r[0] != 0x34); + fail_if(r[1] != 0x12); } END_TEST @@ -21,8 +21,8 @@ START_TEST (test_pack16_le_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]); + fail_if(r[0] != 0xEF); + fail_if(r[1] != 0xFE); } END_TEST @@ -33,8 +33,8 @@ START_TEST (test_pack16_be_1) 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]); + fail_if(r[0] != 0x12); + fail_if(r[1] != 0x34); } END_TEST @@ -45,8 +45,8 @@ START_TEST (test_pack16_be_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]); + fail_if(r[0] != 0xFE); + fail_if(r[1] != 0xEF); } END_TEST @@ -57,7 +57,7 @@ START_TEST (test_unpack16_le_1) v = uc_unpack_16_le(r); - fail_if(v != 0x3412,"was 0x%x",v); + fail_if(v != 0x3412); } END_TEST @@ -68,7 +68,7 @@ START_TEST (test_unpack16_le_2) v = uc_unpack_16_le(r); - fail_if(v != 0xEFFE,"was 0x%x",v); + fail_if(v != 0xEFFE); } END_TEST @@ -79,7 +79,7 @@ START_TEST (test_unpack16_be_1) v = uc_unpack_16_be(r); - fail_if(v != 0x1234,"was 0x%x",v); + fail_if(v != 0x1234); } END_TEST @@ -90,7 +90,7 @@ START_TEST (test_unpack16_be_2) v = uc_unpack_16_be(r); - fail_if(v != 0xFEEF,"was 0x%x",v); + fail_if(v != 0xFEEF); } END_TEST @@ -101,9 +101,9 @@ START_TEST (test_pack24_le_1) 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]); + fail_if(r[0] != 0x56); + fail_if(r[1] != 0x34); + fail_if(r[2] != 0x12); } END_TEST @@ -114,9 +114,9 @@ START_TEST (test_pack24_le_2) 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]); + fail_if(r[0] != 0xF6); + fail_if(r[1] != 0xF7); + fail_if(r[2] != 0xF8); } END_TEST @@ -127,9 +127,9 @@ START_TEST (test_pack24_be_1) 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]); + fail_if(r[0] != 0x12); + fail_if(r[1] != 0x34); + fail_if(r[2] != 0x56); } END_TEST @@ -140,9 +140,9 @@ START_TEST (test_pack24_be_2) 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]); + fail_if(r[0] != 0xF8); + fail_if(r[1] != 0xF7); + fail_if(r[2] != 0xF6); } END_TEST @@ -153,10 +153,10 @@ START_TEST (test_pack32_le_1) 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]); + fail_if(r[0] != 0x78); + fail_if(r[1] != 0x56); + fail_if(r[2] != 0x34); + fail_if(r[3] != 0x12); } END_TEST @@ -167,10 +167,10 @@ START_TEST (test_pack32_le_2) 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]); + fail_if(r[0] != 0xF4); + fail_if(r[1] != 0xF6); + fail_if(r[2] != 0xF7); + fail_if(r[3] != 0xF8); } END_TEST @@ -181,10 +181,10 @@ START_TEST (test_pack32_be_1) 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]); + fail_if(r[3] != 0x78); + fail_if(r[2] != 0x56); + fail_if(r[1] != 0x34); + fail_if(r[0] != 0x12); } END_TEST @@ -195,10 +195,10 @@ START_TEST (test_pack32_be_2) 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]); + fail_if(r[3] != 0xF4); + fail_if(r[2] != 0xF6); + fail_if(r[1] != 0xF7); + fail_if(r[0] != 0xF8); } END_TEST @@ -209,7 +209,7 @@ START_TEST (test_unpack24_le_1) v = uc_unpack_24_le(r); - fail_if(v != 0x563412,"was 0x%x",v); + fail_if(v != 0x563412); } END_TEST @@ -220,7 +220,7 @@ START_TEST (test_unpack24_le_2) v = uc_unpack_24_le(r); - fail_if(v != 0xF6F7F8,"was 0x%x",v); + fail_if(v != 0xF6F7F8); } END_TEST @@ -231,7 +231,7 @@ START_TEST (test_unpack24_be_1) v = uc_unpack_24_be(r); - fail_if(v != 0x123456,"was 0x%x",v); + fail_if(v != 0x123456); } END_TEST @@ -242,7 +242,7 @@ START_TEST (test_unpack24_be_2) v = uc_unpack_24_be(r); - fail_if(v != 0xF8F7F6,"was 0x%x",v); + fail_if(v != 0xF8F7F6); } END_TEST @@ -253,7 +253,7 @@ START_TEST (test_unpack32_le_1) v = uc_unpack_32_le(r); - fail_if(v != 0x78563412,"was 0x%x",v); + fail_if(v != 0x78563412); } END_TEST @@ -264,7 +264,7 @@ START_TEST (test_unpack32_le_2) v = uc_unpack_32_le(r); - fail_if(v != 0xF4F6F7F8,"was 0x%x",v); + fail_if(v != 0xF4F6F7F8); } END_TEST @@ -275,7 +275,7 @@ START_TEST (test_unpack32_be_1) v = uc_unpack_32_be(r); - fail_if(v != 0x12345678,"was 0x%x",v); + fail_if(v != 0x12345678); } END_TEST @@ -286,7 +286,7 @@ START_TEST (test_unpack32_be_2) v = uc_unpack_32_be(r); - fail_if(v != 0xF8F7F6F4,"was 0x%x",v); + fail_if(v != 0xF8F7F6F4); } END_TEST @@ -297,14 +297,14 @@ START_TEST (test_pack64_le_1) 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]); + fail_if(r[0] != 0x88); + fail_if(r[1] != 0x77); + fail_if(r[2] != 0x66); + fail_if(r[3] != 0x55); + fail_if(r[4] != 0x44); + fail_if(r[5] != 0x33); + fail_if(r[6] != 0x22); + fail_if(r[7] != 0x11); } END_TEST @@ -315,14 +315,14 @@ START_TEST (test_pack64_le_2) 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]); + fail_if(r[0] != 0xF8); + fail_if(r[1] != 0xF9); + fail_if(r[2] != 0xFA); + fail_if(r[3] != 0xFB); + fail_if(r[4] != 0xFC); + fail_if(r[5] != 0xFD); + fail_if(r[6] != 0xFE); + fail_if(r[7] != 0xFF); } END_TEST @@ -333,7 +333,7 @@ START_TEST (test_unpack64_le_1) v = uc_unpack_64_le(r); - fail_if(v != 0x8877665544332211ULL,"was 0x%llx",v); + fail_if(v != 0x8877665544332211ULL); } END_TEST @@ -345,7 +345,7 @@ START_TEST (test_unpack64_le_2) v = uc_unpack_64_le(r); - fail_if(v != 0xF8F9FAFBFCFDFEFFULL,"was 0x%llx",v); + fail_if(v != 0xF8F9FAFBFCFDFEFFULL); } END_TEST @@ -356,14 +356,14 @@ START_TEST (test_pack64_be_1) 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]); + fail_if(r[0] != 0x11); + fail_if(r[1] != 0x22); + fail_if(r[2] != 0x33); + fail_if(r[3] != 0x44); + fail_if(r[4] != 0x55); + fail_if(r[5] != 0x66); + fail_if(r[6] != 0x77); + fail_if(r[7] != 0x88); } END_TEST @@ -374,14 +374,14 @@ START_TEST (test_pack64_be_2) 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]); + fail_if(r[0] != 0xFF); + fail_if(r[1] != 0xFE); + fail_if(r[2] != 0xFD); + fail_if(r[3] != 0xFC); + fail_if(r[4] != 0xFB); + fail_if(r[5] != 0xFA); + fail_if(r[6] != 0xF9); + fail_if(r[7] != 0xF8); } END_TEST @@ -392,7 +392,7 @@ START_TEST (test_unpack64_be_1) v = uc_unpack_64_be(r); - fail_if(v != 0x1122334455667788ULL,"was 0x%llx",v); + fail_if(v != 0x1122334455667788ULL); } END_TEST @@ -403,7 +403,7 @@ START_TEST (test_unpack64_be_2) v = uc_unpack_64_be(r); - fail_if(v != 0xFFFEFDFCFBFAF9F8ULL,"was 0x%llx",v); + fail_if(v != 0xFFFEFDFCFBFAF9F8ULL); } END_TEST diff --git a/test/test_ratelimit.c b/test/test_ratelimit.c index 20aa887..6afac0c 100644 --- a/test/test_ratelimit.c +++ b/test/test_ratelimit.c @@ -10,7 +10,7 @@ START_TEST (test_ratelimit_1) uc_ratelimit_init(&r, 30, 2); for (i = 0; i < 30; i++) { - fail_if(!uc_ratelimit_allow(&r, now), "i = %d", i); + fail_if(!uc_ratelimit_allow(&r, now)); } fail_if(uc_ratelimit_allow(&r, now)); } diff --git a/test/test_read_file.c b/test/test_read_file.c index 67f353b..1570b33 100644 --- a/test/test_read_file.c +++ b/test/test_read_file.c @@ -18,8 +18,8 @@ START_TEST (test_read_file_non_existing_file) content = uc_read_file("non existing file 123765", &len, 1000000000); saved_errno = errno; - fail_if(content != NULL); - fail_if(saved_errno == 0); + ck_assert_ptr_null(content); + ck_assert_int_ne(saved_errno, 0); } END_TEST @@ -31,20 +31,20 @@ START_TEST (test_read_file_simple) ssize_t rc; int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); - fail_if(fd == -1); + ck_assert_int_ne(fd, -1); rc = write(fd, "hello", 5); - fail_if(rc != 5, "rc was %ld", (long)rc); + ck_assert_int_eq(rc, 5); 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); + ck_assert_ptr_nonnull(content); + ck_assert_uint_eq(len, 5); + ck_assert_uint_eq(strlen(content), 5); + ck_assert_str_eq("hello", content); free(content); } END_TEST @@ -61,7 +61,7 @@ START_TEST (test_read_file_greater_than_max) fail_if(fd == -1); rc = write(fd, "hello", 5); - fail_if(rc != 5, "rc was %ld", (long)rc); + fail_if(rc != 5); close(fd); @@ -69,8 +69,8 @@ START_TEST (test_read_file_greater_than_max) saved_errno = errno; unlink(filename); - fail_if(content != NULL); - fail_if(saved_errno != EMSGSIZE, "was %d", saved_errno); + ck_assert_ptr_null(content); + ck_assert_int_eq(saved_errno, EMSGSIZE); } END_TEST @@ -87,16 +87,16 @@ START_TEST (test_read_file_boundary) fail_if(fd == -1); rc = write(fd, buf, sizeof buf); - fail_if(rc != sizeof buf, "rc was %ld", (long)rc); + ck_assert_uint_eq(rc, sizeof buf); 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); + ck_assert_ptr_nonnull(content); + ck_assert_uint_eq(len, sizeof buf); + ck_assert_str_eq("foobar", &content[1022]); free(content); } END_TEST @@ -107,10 +107,10 @@ START_TEST (test_read_file_devnull) size_t len = 123; content = uc_read_file("/dev/null", &len, 1024); - fail_if(content == NULL); - fail_if(len != 0); + ck_assert_ptr_nonnull(content); + ck_assert_uint_eq(len, 0); free(content); - + } END_TEST @@ -125,14 +125,14 @@ START_TEST (test_read_file_too_big) fail_if(fd == -1); rc = write(fd, "hello", 5); - fail_if(rc != 5, "rc was %ld", (long)rc); + fail_if(rc != 5); close(fd); content = uc_read_file(filename, &len, 4); - fail_if(errno != EMSGSIZE); - fail_if(content != NULL); + ck_assert_int_eq(errno, EMSGSIZE); + ck_assert_ptr_null(content); unlink(filename); } @@ -147,18 +147,18 @@ START_TEST (test_read_file_big) ssize_t rc; int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); - fail_if(fd == -1); + ck_assert_int_ne(fd, -1); memset(buf, 'a', sizeof buf); rc = write(fd, buf, sizeof buf); - fail_if(rc != sizeof buf, "rc was %ld", (long)rc); + ck_assert_uint_eq(rc, sizeof buf); close(fd); content = uc_read_file(filename, &len, 4096*16); fail_if(content == NULL); - fail_if(len != sizeof buf); - fail_if(memcmp(content, buf, sizeof buf) != 0); + ck_assert_uint_eq(len, sizeof buf); + ck_assert_int_eq(memcmp(content, buf, sizeof buf), 0); free(content); diff --git a/test/test_restart_file.c b/test/test_restart_file.c index 0a2b056..dd6227c 100644 --- a/test/test_restart_file.c +++ b/test/test_restart_file.c @@ -82,7 +82,7 @@ START_TEST (test_restart_counter_garble) ck_assert_int_eq(0, uc_restart_counter_get(&cnt)); rc = uc_restart_counter_init(&cnt, FILE_NAME, 0); - fail_if(rc != UC_RC_OK, "%d", rc); + fail_if(rc != UC_RC_OK); ck_assert_int_eq(1, uc_restart_counter_get(&cnt)); } diff --git a/test/test_runner.c b/test/test_runner.c index 88640ad..86aeba1 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -34,6 +34,7 @@ extern Suite *ticket_lock_suite(void); extern Suite *restart_counter_suite(void); extern Suite *iomux_suite(void); extern Suite *iomux_signal_suite(void); +extern Suite *string_suite(void); extern Suite *ringbuf_suite(void); static suite_func suites[] = { @@ -64,7 +65,10 @@ static suite_func suites[] = { restart_counter_suite, iomux_suite, iomux_signal_suite, + string_suite, +#ifndef __APPLE__ ringbuf_suite +#endif }; diff --git a/test/test_string.c b/test/test_string.c new file mode 100644 index 0000000..6402681 --- /dev/null +++ b/test/test_string.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include "ucore/string.h" +#include "ucore/utils.h" + + +START_TEST (test_getfields) +{ + char str[] = "a;b;c"; + char *letters[5] = {NULL}; + + int rc = uc_getfields(str, letters, 5, 0, ";"); + ck_assert_int_eq(rc, 3); + + + ck_assert_str_eq("a", letters[0]); + ck_assert_str_eq("b", letters[1]); + ck_assert_str_eq("c", letters[2]); +} +END_TEST + +START_TEST (test_getfields_consecutive) +{ + char str[] = "a;;b;c;;;"; + char *letters[7] = {NULL}; + + int rc = uc_getfields(str, letters, 5, 0, ";"); + ck_assert_int_eq(rc, 5); + + + // This result is rather silly, but it's + // how getfields works with mflag=0 + ck_assert_str_eq("a", letters[0]); + ck_assert_str_eq("", letters[1]); + ck_assert_str_eq("b", letters[2]); + ck_assert_str_eq("c", letters[3]); + ck_assert_str_eq(";;", letters[4]); +} +END_TEST + +START_TEST (test_getfields_mflag) +{ + char str[] = "a;b;c"; + char *letters[5] = {NULL}; + + int rc = uc_getfields(str, letters, 5, 1, ";"); + ck_assert_int_eq(rc, 3); + + + ck_assert_str_eq("a", letters[0]); + ck_assert_str_eq("b", letters[1]); + ck_assert_str_eq("c", letters[2]); +} +END_TEST + +START_TEST (test_getfields_consecutive_mflag) +{ + char str[] = "a;;b;c;;;"; + char *letters[7] = {NULL}; + + int rc = uc_getfields(str, letters, 7, 1, ";"); + ck_assert_int_eq(rc, 3); + + + // This result is rather silly, but it's + // how getfields works with mflag=0 + ck_assert_str_eq("a", letters[0]); + ck_assert_str_eq("b", letters[1]); + ck_assert_str_eq("c", letters[2]); +} +END_TEST + +START_TEST (test_getfields_too_many) +{ + char str[] = "a\r\nb\r\nc\r\nd\r\ne"; + char *letters[4] = {NULL}; + + int rc = uc_getfields(str, letters, 4, 0, "\r\n"); + ck_assert_int_eq(rc, 4); + + // This result is rather silly, but it's + // how getfields works with mflag=0 + ck_assert_str_eq("a", letters[0]); + ck_assert_str_eq("", letters[1]); + ck_assert_str_eq("b", letters[2]); + ck_assert_str_eq("\nc\r\nd\r\ne", letters[3]); +} +END_TEST + +START_TEST (test_getfields_too_many_mflag) +{ + char str[] = "a\r\nb\r\nc\r\nd\r\ne"; + char *letters[4] = {NULL}; + + int rc = uc_getfields(str, letters, 4, 1, "\r\n"); + ck_assert_int_eq(rc, 4); + + ck_assert_str_eq("a", letters[0]); + ck_assert_str_eq("b", letters[1]); + ck_assert_str_eq("c", letters[2]); + ck_assert_str_eq("d\r\ne", letters[3]); +} +END_TEST + +START_TEST (test_getfields_empty) +{ + char str[] = ""; + char *letters[4] = {NULL}; + + int rc = uc_getfields(str, letters, 4, 0, ";\r\n"); + ck_assert_int_eq(rc, 1); + ck_assert_str_eq("", letters[0]); + + rc = uc_getfields(str, letters, 4, 1, ";\r\n"); + ck_assert_int_eq(rc, 0); + +} +END_TEST + +START_TEST (test_gettokens) +{ + char str[] = "a;b;c"; + char *letters[5] = {NULL}; + + int rc = uc_gettokens(str, letters, 5,";"); + ck_assert_int_eq(rc, 3); + + + ck_assert_str_eq("a", letters[0]); + ck_assert_str_eq("b", letters[1]); + ck_assert_str_eq("c", letters[2]); +} +END_TEST + +START_TEST (test_gettokens_consecutive) +{ + char str[] = "a;;;b;;c;"; + char *letters[5] = {NULL}; + + int rc = uc_gettokens(str, letters, 5,";"); + ck_assert_int_eq(rc, 3); + + + ck_assert_str_eq("a", letters[0]); + ck_assert_str_eq("b", letters[1]); + ck_assert_str_eq("c", letters[2]); +} +END_TEST + +START_TEST (test_gettokens_empty) +{ + char str[] = ""; + char *letters[5] = {NULL}; + + int rc = uc_gettokens(str, letters, 5,";"); + ck_assert_int_eq(rc, 0); +} +END_TEST + +START_TEST (test_gettokens_quotes) +{ + char str[] = "\"abc\";d;\"e \""; + char *letters[5] = {NULL}; + + int rc = uc_gettokens(str, letters, 5,";"); + ck_assert_int_eq(rc, 3); + + ck_assert_str_eq("abc", letters[0]); + ck_assert_str_eq("d", letters[1]); + ck_assert_str_eq("e ", letters[2]); +} +END_TEST + +START_TEST (test_gettokens_double_quotes) +{ + char str[] = "\"\"abc\"\";d;\"e\"\"f\"\"\""; + char *letters[5] = {NULL}; + + int rc = uc_gettokens(str, letters, 5,";"); + ck_assert_int_eq(rc, 3); + + ck_assert_str_eq("abc", letters[0]); + ck_assert_str_eq("d", letters[1]); + ck_assert_str_eq("e\"f\"", letters[2]); +} +END_TEST + +Suite *string_suite(void) +{ + Suite *s = suite_create("string"); + TCase *tc = tcase_create("string"); + + tcase_add_test(tc, test_getfields); + tcase_add_test(tc, test_getfields_consecutive); + tcase_add_test(tc, test_getfields_mflag); + tcase_add_test(tc, test_getfields_consecutive_mflag); + tcase_add_test(tc, test_getfields_too_many); + tcase_add_test(tc, test_getfields_too_many_mflag); + tcase_add_test(tc, test_getfields_empty); + + tcase_add_test(tc, test_gettokens); + tcase_add_test(tc, test_gettokens_consecutive); + tcase_add_test(tc, test_gettokens_empty); + tcase_add_test(tc, test_gettokens_quotes); + tcase_add_test(tc, test_gettokens_double_quotes); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_strv.c b/test/test_strv.c index f6df841..8e53902 100644 --- a/test/test_strv.c +++ b/test/test_strv.c @@ -135,6 +135,44 @@ START_TEST (test_strv_append_all_nocopy) } END_TEST +START_TEST (test_strv_reverse) +{ + struct UCStrv strv; + + uc_strv_init(&strv); + + uc_strv_append(&strv, "string1"); + + uc_strv_reverse(&strv); + ck_assert_str_eq("string1", strv.strings[0]); + + uc_strv_destroy(&strv); + + uc_strv_init(&strv); + + uc_strv_append(&strv, "string1"); + uc_strv_append(&strv, "string2"); + + uc_strv_reverse(&strv); + ck_assert_str_eq("string2", strv.strings[0]); + ck_assert_str_eq("string1", strv.strings[1]); + + uc_strv_destroy(&strv); + + uc_strv_init(&strv); + + uc_strv_append(&strv, "string1"); + uc_strv_append(&strv, "string2"); + uc_strv_append(&strv, "string3"); + + uc_strv_reverse(&strv); + ck_assert_str_eq("string3", strv.strings[0]); + ck_assert_str_eq("string2", strv.strings[1]); + ck_assert_str_eq("string1", strv.strings[2]); + + uc_strv_destroy(&strv); +} +END_TEST Suite *strv_suite(void) { @@ -147,6 +185,7 @@ Suite *strv_suite(void) tcase_add_test(tc, test_strv_null_terminate); tcase_add_test(tc, test_strv_append_all_copy); tcase_add_test(tc, test_strv_append_all_nocopy); + tcase_add_test(tc, test_strv_reverse); suite_add_tcase(s, tc);