├── libc ├── src │ ├── fslc_stdin.c │ ├── fslc_stdout.c │ ├── fslc_getchar.c │ ├── fslc_putchar.c │ ├── fslc_vprintf.c │ ├── fslc_strcpy.c │ ├── fslc_strlen.c │ ├── fslc_strcpy_e.c │ ├── fslc_strchr.c │ ├── fslc_strcmp.c │ ├── fslc_printf.c │ ├── fslc_strncpy_impl.c │ ├── fslc_strncmp.c │ ├── fslc_strncpy.c │ ├── fslc_ungetc.c │ ├── fslc_fprintf.c │ ├── fslc_strncpy_e.c │ ├── fslc_getc.c │ ├── fslc_fputc.c │ ├── fslc_fputs_impl.c │ ├── fslc_strpbrk.c │ ├── fslc_bsearch.c │ ├── fslc_fputs.c │ ├── fslc_strspn.c │ ├── fslc_fgets.c │ ├── fslc_strtok_r.c │ ├── fslc_puts.c │ ├── fslc_memset.c │ ├── fslc_bsearch_i.c │ ├── fslc_fread.c │ ├── fslc_strstr.c │ ├── fslc_fwrite.c │ ├── fslc_memset_l.c │ ├── fslc_memcmp.c │ ├── fslc_memcpy.c │ ├── fslc_memmove.c │ └── fslc_vfprintf.c ├── include │ ├── stdio.h │ ├── assert.h │ ├── stdlib.h │ ├── string.h │ └── fslc │ │ ├── stdlibx.h │ │ ├── fslc_stdlib.h │ │ ├── fslc_assert.h │ │ ├── stringx.h │ │ ├── fslc_string.h │ │ └── fslc_stdio.h ├── coverage.sh ├── CMakeLists.txt └── Libc.project ├── tests ├── misc_utils.h ├── strmod_fixture.cpp ├── strlen_tests.cpp ├── strmod_fixture.h ├── assert_nd_tests.cpp ├── strchr_tests.cpp ├── assert_d_tests.cpp ├── CMakeLists.txt ├── strcpy_tests.cpp ├── strspn_tests.cpp ├── strpbrk_tests.cpp ├── getc_tests.cpp ├── strstr_tests.cpp ├── stdio_fixture.h ├── strncpy_tests.cpp ├── strcmp_tests.cpp ├── fread_tests.cpp ├── main.cpp ├── stdio_fixture.cpp ├── fgets_tests.cpp ├── strtok_tests.cpp ├── strncmp_tests.cpp ├── memmove_tests.cpp ├── putc_tests.cpp ├── memcmp_tests.cpp ├── fwrite_tests.cpp ├── memcpy_tests.cpp ├── memset_tests.cpp ├── bsearch_i_tests.cpp ├── bsearch_tests.cpp ├── Tests.project ├── puts_tests.cpp └── printf_tests.cpp ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── cross-toolchain.cmake ├── FsLibc.workspace ├── LICENSE └── README.md /libc/src/fslc_stdin.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | FSLC_FILE *fslc_stdin; 4 | -------------------------------------------------------------------------------- /libc/src/fslc_stdout.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | FSLC_FILE *fslc_stdout; 4 | -------------------------------------------------------------------------------- /libc/src/fslc_getchar.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int fslc_getchar(void) 4 | { 5 | return fslc_getc(fslc_stdin); 6 | } 7 | -------------------------------------------------------------------------------- /libc/include/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _STD_STDIO_H 2 | #define _STD_STDIO_H 3 | 4 | #include "fslc/fslc_stdio.h" 5 | 6 | #endif /* _STD_STDIO_H */ 7 | -------------------------------------------------------------------------------- /libc/src/fslc_putchar.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int fslc_putchar(int c) 4 | { 5 | return fslc_fputc(c, fslc_stdout); 6 | } 7 | -------------------------------------------------------------------------------- /libc/include/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef _STD_ASSERT_H 2 | #define _STD_ASSERT_H 3 | 4 | #include "fslc/fslc_assert.h" 5 | 6 | #endif /* _STD_ASSERT_H */ 7 | -------------------------------------------------------------------------------- /libc/include/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef _STD_STDLIB_H 2 | #define _STD_STDLIB_H 3 | 4 | #include "fslc/fslc_stdlib.h" 5 | 6 | #endif /* _STD_STDLIB_H */ 7 | -------------------------------------------------------------------------------- /libc/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STD_STRING_H 2 | #define _STD_STRING_H 3 | 4 | #include "fslc/fslc_string.h" 5 | 6 | #endif /* _STD_STRING_H */ 7 | -------------------------------------------------------------------------------- /tests/misc_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef MISC_UTILS 2 | #define MISC_UTILS 3 | 4 | #define SIGNOF(X) ((X) > 0 ? 1 : ((X) < 0 ? -1 : 0)) 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /libc/coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | lcov -c --rc lcov_branch_coverage=1 -d CMakeFiles/fslc.dir/src -o coverage.info 3 | genhtml coverage.info --branch-coverage -o cov_report 4 | -------------------------------------------------------------------------------- /libc/src/fslc_vprintf.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int fslc_vprintf(const char *format, va_list arg) 4 | { 5 | return fslc_vfprintf(fslc_stdout, format, arg); 6 | } 7 | -------------------------------------------------------------------------------- /libc/src/fslc_strcpy.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | #include "stringx.h" 3 | 4 | char *fslc_strcpy(char *dest, const char *src) 5 | { 6 | fslc_strcpy_e(dest, src); 7 | return dest; 8 | } 9 | -------------------------------------------------------------------------------- /libc/src/fslc_strlen.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | size_t fslc_strlen(const char *str) 4 | { 5 | size_t res = 0; 6 | for(; *str; ++str) ++res; 7 | 8 | return res; 9 | } 10 | -------------------------------------------------------------------------------- /libc/src/fslc_strcpy_e.c: -------------------------------------------------------------------------------- 1 | #include "stringx.h" 2 | 3 | char *fslc_strcpy_e(char *dest, const char *src) 4 | { 5 | for(; *src; ++src, ++dest) 6 | *dest = *src; 7 | 8 | *dest = 0; 9 | return dest; 10 | } 11 | -------------------------------------------------------------------------------- /libc/src/fslc_strchr.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | char *fslc_strchr(const char *str, int c) 4 | { 5 | for (;*str; ++str) 6 | if (*str == c) 7 | return (char *)str; 8 | 9 | return NULL; 10 | } 11 | -------------------------------------------------------------------------------- /libc/src/fslc_strcmp.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | int fslc_strcmp(const char *str1, const char *str2) 4 | { 5 | for( ; *str1 && *str1 == *str2; ++str1, ++str2); 6 | 7 | return *((unsigned char *)str1) - *((unsigned char *)str2); 8 | } 9 | -------------------------------------------------------------------------------- /tests/strmod_fixture.cpp: -------------------------------------------------------------------------------- 1 | #include "strmod_fixture.h" 2 | #include 3 | 4 | StrModFixture::StrModFixture() 5 | { 6 | memset(testString, 0xFF, sizeof(testString)); 7 | memset(expectedString, 0xFF, sizeof(expectedString)); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /libc/src/fslc_printf.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int fslc_printf(const char *format, ...) 4 | { 5 | va_list args; 6 | va_start(args, format); 7 | int r = fslc_vfprintf(fslc_stdout, format, args); 8 | va_end(args); 9 | return r; 10 | } 11 | -------------------------------------------------------------------------------- /libc/src/fslc_strncpy_impl.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char *_fslc_strncpy_impl(char *dest, const char *src, size_t len) 4 | { 5 | for(; *src && len > 1; ++src, ++dest, --len) 6 | *dest = *src; 7 | 8 | *dest = *src; 9 | return dest; 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .build-debug 2 | .codelite 3 | Debug/ 4 | Release/ 5 | cov_report/ 6 | /Makefile 7 | *.mk 8 | *.txt 9 | !CMakeLists.txt 10 | CMakeFiles/ 11 | *.cmake 12 | !cross-toolchain.cmake 13 | Makefile 14 | *.a 15 | build/ 16 | Testing/ 17 | coverage.info 18 | tests/tests 19 | -------------------------------------------------------------------------------- /libc/src/fslc_strncmp.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | int fslc_strncmp(const char *str1, const char *str2, size_t num) 4 | { 5 | for( ; *str1 && *str1 == *str2 && num > 1; ++str1, ++str2, --num); 6 | 7 | return *((unsigned char *)str1) - *((unsigned char *)str2); 8 | } 9 | -------------------------------------------------------------------------------- /libc/src/fslc_strncpy.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | char *_fslc_strncpy_impl(char *dest, const char *src, size_t len); 4 | 5 | char *fslc_strncpy(char *dest, const char *src, size_t len) 6 | { 7 | _fslc_strncpy_impl(dest, src, len); 8 | return dest; 9 | } 10 | -------------------------------------------------------------------------------- /libc/src/fslc_ungetc.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int fslc_ungetc(int c, FSLC_FILE *stream) 4 | { 5 | if (stream->ungetc_buf >= 0) 6 | { 7 | return -1; 8 | } 9 | stream->ungetc_buf = (unsigned char)c; 10 | return stream->ungetc_buf; 11 | } 12 | -------------------------------------------------------------------------------- /libc/src/fslc_fprintf.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int fslc_fprintf(FSLC_FILE *stream, const char *format, ...) 4 | { 5 | va_list args; 6 | va_start(args, format); 7 | int r = fslc_vfprintf(stream, format, args); 8 | va_end(args); 9 | return r; 10 | } 11 | -------------------------------------------------------------------------------- /libc/src/fslc_strncpy_e.c: -------------------------------------------------------------------------------- 1 | #include "stringx.h" 2 | 3 | char *_fslc_strncpy_impl(char *dest, const char *src, size_t len); 4 | 5 | char *fslc_strncpy_e(char *dest, const char *src, size_t len) 6 | { 7 | char *r = _fslc_strncpy_impl(dest, src, len); 8 | return *r ? r + 1: r; 9 | } 10 | -------------------------------------------------------------------------------- /libc/src/fslc_getc.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int fslc_getc(FSLC_FILE *stream) 4 | { 5 | if (stream->ungetc_buf >= 0) 6 | { 7 | int retval = stream->ungetc_buf; 8 | stream->ungetc_buf = -1; 9 | return retval; 10 | } 11 | return stream->getc(stream); 12 | } 13 | -------------------------------------------------------------------------------- /libc/src/fslc_fputc.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int fslc_fputc(int c, FSLC_FILE *stream) 4 | { 5 | if (stream->pre_output) stream->pre_output(stream); 6 | 7 | int r = stream->putc(c, stream); 8 | 9 | if (stream->post_output) stream->post_output(stream); 10 | 11 | return r; 12 | } 13 | -------------------------------------------------------------------------------- /libc/src/fslc_fputs_impl.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int _fslc_fputs_impl(const char *str, FSLC_FILE *stream) 4 | { 5 | int res = 0; 6 | for (;*str; ++str) 7 | { 8 | int pr = stream->putc(*str, stream); 9 | if (pr < 0) return pr; 10 | ++res; 11 | } 12 | return res; 13 | } 14 | -------------------------------------------------------------------------------- /libc/src/fslc_strpbrk.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | char *fslc_strpbrk(const char *str, const char *delim) 4 | { 5 | for (; *str; ++str) 6 | { 7 | const char *d; 8 | for (d = delim; *d; ++d) 9 | if (*str == *d) 10 | return (char *)str; 11 | } 12 | 13 | return NULL; 14 | } 15 | -------------------------------------------------------------------------------- /tests/strlen_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | SUITE(StrLen) 6 | { 7 | TEST(BasicTest) 8 | { 9 | const char *txt = "Test string"; 10 | 11 | int r = fslc_strlen(txt); 12 | int e = strlen(txt); 13 | 14 | CHECK_EQUAL(e, r); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB fslc_SRC src/*.c) 2 | file(GLOB fslc_INC include/fslc/*.h) 3 | file(GLOB fslc_SINC include/*.h) 4 | 5 | include_directories(include/fslc) 6 | add_library(fslc ${fslc_SRC}) 7 | 8 | install(TARGETS fslc DESTINATION lib) 9 | install(FILES ${fslc_SINC} DESTINATION include) 10 | install(FILES ${fslc_INC} DESTINATION include/fslc) 11 | -------------------------------------------------------------------------------- /tests/strmod_fixture.h: -------------------------------------------------------------------------------- 1 | #ifndef STRMOD_FIXTURE_H 2 | #define STRMOD_FIXTURE_H 3 | 4 | #include "fslc_string.h" 5 | #include "stringx.h" 6 | 7 | 8 | struct StrModFixture 9 | { 10 | static const int MAXLEN = 100; 11 | char testString[MAXLEN]; 12 | char expectedString[MAXLEN]; 13 | 14 | StrModFixture(); 15 | }; 16 | 17 | 18 | #endif /* STRMOD_FIXTURE_H */ 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | language: cpp 4 | 5 | addons: 6 | apt: 7 | sources: 8 | - ubuntu-toolchain-r-test 9 | packages: 10 | - gcc-5 11 | - g++-5 12 | - libunittest++-dev 13 | 14 | script: 15 | - export CC=/usr/bin/gcc-5 16 | - export CXX=/usr/bin/g++-5 17 | - cmake -DCMAKE_BUILD_TYPE=RelCheck . 18 | - make 19 | - make test 20 | -------------------------------------------------------------------------------- /libc/src/fslc_bsearch.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdlib.h" 2 | #include "stdlibx.h" 3 | 4 | void *fslc_bsearch(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *)) 5 | { 6 | int sidx = fslc_bsearch_i(key, base, num, size, cmp_proc); 7 | 8 | if (sidx < 0) 9 | return NULL; 10 | 11 | return (char *)base + (sidx * size); 12 | } 13 | -------------------------------------------------------------------------------- /libc/src/fslc_fputs.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int _fslc_fputs_impl(const char *str, FSLC_FILE *stream); 4 | 5 | int fslc_fputs(const char *str, FSLC_FILE *stream) 6 | { 7 | if (stream->pre_output) stream->pre_output(stream); 8 | 9 | int r = _fslc_fputs_impl(str, stream); 10 | 11 | if (stream->post_output) stream->post_output(stream); 12 | 13 | return r; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /libc/src/fslc_strspn.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | size_t fslc_strspn(const char *str, const char *delim) 4 | { 5 | size_t r; 6 | 7 | for (r = 0; *str; ++str, ++r) 8 | { 9 | const char *d; 10 | for (d = delim; *d; ++d) 11 | if (*str == *d) // skip to next if found 12 | break; 13 | 14 | if (*d == 0) // inner loop exited on \0 - char was not there 15 | break; 16 | } 17 | return r; 18 | } 19 | -------------------------------------------------------------------------------- /tests/assert_nd_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Ensure that desired assertion mode is selected */ 4 | #ifndef NDEBUG 5 | #define NDEBUG 6 | #endif 7 | 8 | #include "fslc_assert.h" 9 | 10 | SUITE(AssertDisabled) 11 | { 12 | TEST(AssertPass) 13 | { 14 | int val = 4; 15 | 16 | fslc_assert(val == 4); 17 | } 18 | 19 | TEST(AssertFailIgnored) 20 | { 21 | int val = 4; 22 | 23 | fslc_assert(val == 5); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project (FsLibc) 3 | 4 | enable_testing() 5 | 6 | set (FsLibc_VERSION_MAJOR 0) 7 | set (FsLibc_VERSION_MINOR 8) 8 | 9 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Wextra -fprofile-arcs -ftest-coverage -DALT_FSLC_NAMES") 10 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wall -Wextra") 11 | set(CMAKE_C_FLAGS_RELCHECK "${CMAKE_C_FLAGS_RELEASE} -DALT_FSLC_NAMES") 12 | 13 | add_subdirectory(libc) 14 | add_subdirectory(tests) 15 | -------------------------------------------------------------------------------- /libc/src/fslc_fgets.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | char *fslc_fgets(char *str, int num, FSLC_FILE *stream) 4 | { 5 | int i; 6 | --num; 7 | for (i = 0; i < num; ++i) 8 | { 9 | int c = fslc_getc(stream); 10 | if (c < 0) 11 | { 12 | str[i] = 0; 13 | break; 14 | } 15 | str[i] = c; 16 | 17 | if (c == '\n') 18 | { 19 | str[i+1] = 0; 20 | break; 21 | } 22 | } 23 | str[num] = 0; 24 | return str; 25 | } 26 | -------------------------------------------------------------------------------- /cross-toolchain.cmake: -------------------------------------------------------------------------------- 1 | SET(CMAKE_SYSTEM_NAME Generic) 2 | 3 | # specify the cross compiler 4 | SET(CMAKE_C_COMPILER arm-elf-eabi-gcc) 5 | SET(CMAKE_CXX_COMPILER arm-elf-eabi-g++) 6 | 7 | # use this if CMAKE complains about '-rdynamic' 8 | SET(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 9 | 10 | # search for programs in the build host directories 11 | SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 12 | # for libraries and headers in the target directories 13 | SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 14 | SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 15 | -------------------------------------------------------------------------------- /libc/include/fslc/stdlibx.h: -------------------------------------------------------------------------------- 1 | #ifndef FSLC_STDLIBX_H 2 | #define FSLC_STDLIBX_H 3 | 4 | #include 5 | 6 | #ifndef ALT_FSLC_NAMES 7 | 8 | #define fslc_bsearch_i bsearch_i 9 | 10 | #endif /* ALT_FSLC_NAMES */ 11 | 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif /* __cplusplus */ 16 | 17 | int fslc_bsearch_i(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *)); 18 | 19 | #ifdef __cplusplus 20 | } /* extern "C" */ 21 | #endif /* __cplusplus */ 22 | 23 | #endif /* FSLC_STDLIBX_H */ 24 | -------------------------------------------------------------------------------- /libc/src/fslc_strtok_r.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | char *fslc_strtok_r(char *str, const char *delim, char **save_p) 4 | { 5 | if (str) 6 | *save_p = str; 7 | 8 | if (*save_p == NULL) 9 | return NULL; 10 | 11 | char *r = *save_p + fslc_strspn(*save_p, delim); 12 | 13 | char *p = fslc_strpbrk(r, delim); 14 | 15 | if (p) 16 | { 17 | *(p++) = 0; 18 | *save_p = p; 19 | } 20 | else 21 | { 22 | if (*r == 0) r = NULL; 23 | *save_p = NULL; 24 | } 25 | 26 | return r; 27 | } 28 | -------------------------------------------------------------------------------- /libc/include/fslc/fslc_stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef FSLC_STDLIB_H 2 | #define FSLC_STDLIB_H 3 | 4 | #include 5 | 6 | #ifndef ALT_FSLC_NAMES 7 | 8 | #define fslc_bsearch bsearch 9 | 10 | #endif /* ALT_FSLC_NAMES */ 11 | 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif /* __cplusplus */ 16 | 17 | 18 | void *fslc_bsearch(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *)); 19 | 20 | 21 | #ifdef __cplusplus 22 | } /* extern "C" */ 23 | #endif /* __cplusplus */ 24 | 25 | #endif /* FSLC_STDLIB_H */ 26 | -------------------------------------------------------------------------------- /libc/src/fslc_puts.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | int _fslc_fputs_impl(const char *str, FSLC_FILE *stream); 4 | 5 | int fslc_puts(const char *str) 6 | { 7 | if (fslc_stdout->pre_output) fslc_stdout->pre_output(fslc_stdout); 8 | 9 | int r = _fslc_fputs_impl(str, fslc_stdout); 10 | 11 | if (r >= 0) 12 | { 13 | int nlr = fslc_stdout->putc('\n', fslc_stdout); 14 | if (nlr < 0) 15 | r = nlr; 16 | } 17 | 18 | if (fslc_stdout->post_output) fslc_stdout->post_output(fslc_stdout); 19 | 20 | return r; 21 | } 22 | -------------------------------------------------------------------------------- /tests/strchr_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | SUITE(StrChr) 6 | { 7 | TEST(BasicTest) 8 | { 9 | const char *txt = "Test string"; 10 | 11 | const char *r = fslc_strchr(txt, 's'); 12 | const char *e = strchr(txt, 's'); 13 | 14 | CHECK_EQUAL((uintptr_t)e, (uintptr_t)r); 15 | } 16 | 17 | TEST(NotFoundTest) 18 | { 19 | const char *txt = "Test string"; 20 | 21 | const char *r = fslc_strchr(txt, 'm'); 22 | const char *e = strchr(txt, 'm'); 23 | 24 | CHECK_EQUAL((uintptr_t)e, (uintptr_t)r); // compare pointer values 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /libc/src/fslc_memset.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | #include "stringx.h" 3 | 4 | void *fslc_memset(void *ptr, int value, size_t num) 5 | { 6 | /* Will use memset_l() to actually fill the memory region. If value is non-zero, we need 7 | * to replicate lowest byte to all the long's bytes. 8 | */ 9 | if (value) 10 | { 11 | unsigned char c_val = value; 12 | unsigned long l_val = (c_val << 0) | (c_val << 8) | (c_val << 16) | (c_val << 24); 13 | 14 | #if __SIZEOF_LONG__ == 8 15 | l_val |= l_val << 32; 16 | #endif 17 | 18 | return fslc_memset_l(ptr, l_val, num); 19 | } 20 | else 21 | return fslc_memset_l(ptr, value, num); 22 | } 23 | -------------------------------------------------------------------------------- /FsLibc.workspace: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /libc/src/fslc_bsearch_i.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fslc_bsearch_i(const void *key, const void *base, size_t num, size_t size, int (*cmp_proc)(const void *, const void *)) 4 | { 5 | int lo = 0; 6 | int hi = num - 1; 7 | 8 | char *cbase = (char *)base; 9 | 10 | while (lo <= hi) 11 | { 12 | int i = lo + ((hi - lo) >> 1); 13 | 14 | char *ptr = cbase + (i * size); 15 | int cmp = cmp_proc(key, ptr); 16 | 17 | if (cmp == 0) 18 | return i; 19 | 20 | if (cmp > 0) 21 | { 22 | lo = i + 1; 23 | } 24 | else 25 | { 26 | hi = i - 1; 27 | } 28 | } 29 | 30 | return ~lo; 31 | } 32 | -------------------------------------------------------------------------------- /tests/assert_d_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Ensure that desired assertion mode is selected */ 4 | #ifdef NDEBUG 5 | #undef NDEBUG 6 | #endif 7 | 8 | #include "fslc_assert.h" 9 | 10 | SUITE(AssertEnabled) 11 | { 12 | TEST(AssertPass) 13 | { 14 | int val = 4; 15 | 16 | fslc_assert(val == 4); 17 | } 18 | 19 | TEST(AssertFail) 20 | { 21 | int val = 4; 22 | 23 | CHECK_THROW( 24 | fslc_assert(val == 5), 25 | UnitTest::AssertException 26 | ); 27 | } 28 | } 29 | 30 | extern "C" void __fslc_assert_fail(const char *expr, const char *file, unsigned int line, const char *) 31 | { 32 | throw UnitTest::AssertException(expr, file, line); 33 | } 34 | -------------------------------------------------------------------------------- /libc/src/fslc_fread.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | 4 | static size_t _fslc_fread_impl(void *ptr, size_t count, FSLC_FILE *stream); 5 | 6 | size_t fslc_fread(void *ptr, size_t size, size_t count, FSLC_FILE *stream) 7 | { 8 | size_t res = _fslc_fread_impl(ptr, count * size, stream); 9 | 10 | return size > 0 ? res / size : 0; 11 | } 12 | 13 | 14 | static size_t _fslc_fread_impl(void *ptr, size_t count, FSLC_FILE *stream) 15 | { 16 | size_t i; 17 | 18 | unsigned char *data = (unsigned char *)ptr; 19 | 20 | for (i=0; i < count; ++i, ++data) 21 | { 22 | int r = fslc_getc(stream); 23 | if (r < 0) 24 | { 25 | return i; 26 | } 27 | *data = r; 28 | } 29 | return count; 30 | } 31 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB tests_SRC *.cpp) 2 | 3 | add_definitions(-std=c++11) 4 | 5 | find_package(PkgConfig) 6 | pkg_check_modules(PC_UTPP QUIET unittest++) 7 | 8 | include_directories(${PROJECT_SOURCE_DIR}/libc/include/fslc) 9 | include_directories(${PC_UTPP_INCLUDE_DIRS}) 10 | add_executable(tests ${tests_SRC}) 11 | 12 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DALT_FSLC_NAMES") 13 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") 14 | set(CMAKE_CXX_FLAGS_RELCHECK "${CMAKE_CXX_FLAGS_RELEASE} -DALT_FSLC_NAMES") 15 | 16 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs") 17 | 18 | target_link_libraries(tests fslc) 19 | target_link_libraries(tests ${PC_UTPP_LIBRARIES}) 20 | 21 | add_test(libTests tests) 22 | 23 | -------------------------------------------------------------------------------- /libc/src/fslc_strstr.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | 3 | char *fslc_strstr(const char *search_in, const char *search_for) 4 | { 5 | while (*search_in) 6 | { 7 | char *rc = fslc_strchr(search_in, search_for[0]); // find first char 8 | 9 | if (rc) 10 | { 11 | const char *si = rc + 1, *sf = search_for + 1; // search strcmp-style from second char 12 | for( ; *si && *si == *sf; ++si, ++sf); 13 | 14 | if (*sf == 0) return rc; // end of search-for - found result 15 | 16 | search_in = rc + 1; // not this one, continue from next char 17 | } 18 | else 19 | return NULL; // did not find first char - exit 20 | } 21 | 22 | return NULL; // reached end of source - did not find 23 | } 24 | -------------------------------------------------------------------------------- /libc/include/fslc/fslc_assert.h: -------------------------------------------------------------------------------- 1 | #ifndef FSLC_ASSERT_H 2 | #define FSLC_ASSERT_H 3 | 4 | #ifndef ALT_FSLC_NAMES 5 | 6 | #define fslc_assert assert 7 | 8 | #endif /* ALT_FSLC_NAMES */ 9 | 10 | 11 | #ifdef NDEBUG 12 | 13 | #define fslc_assert(expr) ((void)0) 14 | 15 | #else /* NDEBUG */ 16 | 17 | /* Note: __PRETTY_FUNCTION__ is GCC specific */ 18 | #define fslc_assert(expr) ((expr) ? (void)0 : __fslc_assert_fail(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__)) 19 | 20 | #endif /* NDEBUG */ 21 | 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif /* __cplusplus */ 26 | 27 | 28 | void __fslc_assert_fail(const char *expr, const char *file, unsigned int line, const char *func); 29 | 30 | 31 | #ifdef __cplusplus 32 | } /* extern "C" */ 33 | #endif /* __cplusplus */ 34 | 35 | #endif /* FSLC_ASSERT_H */ 36 | -------------------------------------------------------------------------------- /tests/strcpy_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "strmod_fixture.h" 4 | #include 5 | 6 | SUITE(StrCpy) 7 | { 8 | TEST_FIXTURE(StrModFixture, BasicTest) 9 | { 10 | char *cc = fslc_strcpy(testString,"Hello, World!"); 11 | strcpy(expectedString,"Hello, World!"); 12 | 13 | CHECK_EQUAL((uintptr_t)testString, (uintptr_t)cc); 14 | 15 | CHECK_ARRAY_EQUAL(expectedString, testString, MAXLEN); 16 | } 17 | 18 | TEST_FIXTURE(StrModFixture, StrCpyEResultTest) 19 | { 20 | char *cc = fslc_strcpy_e(testString,"Hello, World!"); 21 | strcpy(expectedString,"Hello, World!"); 22 | 23 | CHECK_EQUAL((uintptr_t)testString+strlen(expectedString), (uintptr_t)cc); 24 | 25 | CHECK_ARRAY_EQUAL(expectedString, testString, MAXLEN); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/strspn_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | SUITE(StrSpn) 6 | { 7 | TEST(BeginningTest) 8 | { 9 | const char *txt = "*^*#^*The text continues"; 10 | 11 | size_t r = fslc_strspn(txt, "#*^"); 12 | size_t e = strspn(txt, "#*^"); 13 | 14 | CHECK_EQUAL(e, r); 15 | } 16 | 17 | TEST(ZeroResTest) 18 | { 19 | const char *txt = "This is *^*#^*"; 20 | 21 | size_t r = fslc_strspn(txt, "#*^"); 22 | size_t e = strspn(txt, "#*^"); 23 | 24 | CHECK_EQUAL(e, r); 25 | } 26 | 27 | TEST(AllTest) 28 | { 29 | const char *txt = "*^*#^*^^**###"; 30 | 31 | size_t r = fslc_strspn(txt, "#*^"); 32 | size_t e = strspn(txt, "#*^"); 33 | 34 | CHECK_EQUAL(e, r); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /libc/include/fslc/stringx.h: -------------------------------------------------------------------------------- 1 | #ifndef FSLC_STRINGX_H 2 | #define FSLC_STRINGX_H 3 | 4 | #include 5 | 6 | #ifndef ALT_FSLC_NAMES 7 | 8 | #define fslc_memset_l memset_l 9 | #define fslc_strcpy_e strcpy_e 10 | #define fslc_strncpy_e strncpy_e 11 | 12 | #endif /* ALT_FSLC_NAMES */ 13 | 14 | #if __SIZEOF_LONG__ == 4 15 | #define memset_32 memset_l 16 | #elif __SIZEOF_LONG__ == 8 17 | #define memset_32(A, V, S) memset_l(A, (((unsigned long)(V)<<32)|(V)), S) 18 | #endif 19 | 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif /* __cplusplus */ 24 | 25 | void *fslc_memset_l(void *ptr, unsigned long value, size_t num); 26 | char *fslc_strcpy_e(char *dest, const char *src); 27 | char *fslc_strncpy_e(char *dest, const char *src, size_t len); 28 | 29 | #ifdef __cplusplus 30 | } /* extern "C" */ 31 | #endif /* __cplusplus */ 32 | 33 | #endif /* FSLC_STRINGX_H */ 34 | -------------------------------------------------------------------------------- /libc/src/fslc_fwrite.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | static size_t _fslc_fwrite_impl(const void *ptr, size_t count, FSLC_FILE *stream); 4 | 5 | size_t fslc_fwrite(const void *ptr, size_t size, size_t count, FSLC_FILE *stream) 6 | { 7 | if (stream->pre_output) stream->pre_output(stream); 8 | 9 | size_t res = _fslc_fwrite_impl(ptr, count * size, stream); 10 | 11 | if (stream->post_output) stream->post_output(stream); 12 | 13 | return size > 0 ? res / size : 0; 14 | } 15 | 16 | 17 | static size_t _fslc_fwrite_impl(const void *ptr, size_t count, FSLC_FILE *stream) 18 | { 19 | size_t i; 20 | 21 | unsigned char *data = (unsigned char *)ptr; 22 | 23 | for (i=0; i < count; ++i, ++data) 24 | { 25 | int r = stream->putc(*data, stream); 26 | if (r < 0) 27 | { 28 | return i; 29 | } 30 | } 31 | return count; 32 | } 33 | -------------------------------------------------------------------------------- /libc/src/fslc_memset_l.c: -------------------------------------------------------------------------------- 1 | #include "stringx.h" 2 | #include 3 | 4 | void *fslc_memset_l(void *ptr, unsigned long value, size_t num) 5 | { 6 | unsigned char *b_src = (unsigned char *)&value; 7 | unsigned char *b_dst = (unsigned char *)ptr; 8 | 9 | /* Byte by byte - to aligned word address */ 10 | b_src += ((uintptr_t)b_dst & (sizeof(unsigned long)-1)); 11 | for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && num > 0; b_dst++,b_src++,num--) 12 | { 13 | *b_dst = *b_src; 14 | } 15 | 16 | /* All aligned */ 17 | unsigned long *w_dst = (unsigned long *)b_dst; 18 | for (;num >= sizeof(unsigned long); w_dst++,num -= sizeof(unsigned long)) 19 | { 20 | *w_dst= value; 21 | } 22 | 23 | /* Unaligned ending */ 24 | b_src = (unsigned char *)&value; 25 | b_dst = (unsigned char *)w_dst; 26 | for (; num > 0; b_dst++,b_src++,num--) 27 | { 28 | *b_dst = *b_src; 29 | } 30 | return ptr; 31 | } 32 | -------------------------------------------------------------------------------- /tests/strpbrk_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | SUITE(StrPBrk) 6 | { 7 | TEST(BasicTest) 8 | { 9 | const char *txt = "Delimited,string;by.some-chars"; 10 | 11 | const char *r1 = fslc_strpbrk(txt, ",;.-"); 12 | const char *e1 = fslc_strpbrk(txt, ",;.-"); 13 | 14 | CHECK_EQUAL((uintptr_t)e1, (uintptr_t)r1); 15 | 16 | const char *r2 = fslc_strpbrk(r1+1, ",;.-"); 17 | const char *e2 = fslc_strpbrk(e1+1, ",;.-"); 18 | 19 | CHECK_EQUAL((uintptr_t)e2, (uintptr_t)r2); 20 | 21 | const char *r3 = fslc_strpbrk(r2+1, ",;.-"); 22 | const char *e3 = fslc_strpbrk(e2+1, ",;.-"); 23 | 24 | CHECK_EQUAL((uintptr_t)e3, (uintptr_t)r3); 25 | } 26 | 27 | TEST(NotFoundTest) 28 | { 29 | const char *txt = "Delimited,string;by.some-chars"; 30 | 31 | const char *r1 = fslc_strpbrk(txt, "#!$%"); 32 | const char *e1 = fslc_strpbrk(txt, "#!$%"); 33 | 34 | CHECK_EQUAL((uintptr_t)e1, (uintptr_t)r1); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /libc/src/fslc_memcmp.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | #include 3 | 4 | int fslc_memcmp(const void *ptr1, const void *ptr2, size_t num) 5 | { 6 | unsigned char *b_p1 = (unsigned char *)ptr1; 7 | unsigned char *b_p2 = (unsigned char *)ptr2; 8 | 9 | for (;((uintptr_t)b_p1 & (sizeof(long)-1)) && num > 0; ++b_p1, ++b_p2, --num) 10 | { 11 | if (*b_p1 != *b_p2) 12 | { 13 | return *b_p1 > *b_p2 ? 1 : -1; 14 | } 15 | } 16 | 17 | unsigned long *w_p1 = (unsigned long *)b_p1; 18 | unsigned long *w_p2 = (unsigned long *)b_p2; 19 | for (;num >= sizeof(unsigned long); ++w_p1, ++w_p2, num -= sizeof(unsigned long)) 20 | { 21 | if (*w_p1 != *w_p2) 22 | { 23 | return *w_p1 > *w_p2 ? 1 : -1; 24 | } 25 | } 26 | 27 | b_p1 = (unsigned char *)w_p1; 28 | b_p2 = (unsigned char *)w_p2; 29 | for (; num > 0; ++b_p1, ++b_p2, --num) 30 | { 31 | if (*b_p1 != *b_p2) 32 | { 33 | return *b_p1 > *b_p2 ? 1 : -1; 34 | } 35 | } 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 Jurģis Brigmanis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/getc_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stdio_fixture.h" 4 | 5 | SUITE(FGetC) 6 | { 7 | TEST_FIXTURE(StdIOFixture, FGetCBasicTest) 8 | { 9 | istring.str("Hello"); 10 | fslc_stdin = &stream; 11 | 12 | int h = fslc_getchar(); 13 | int e = fslc_getchar(); 14 | int l1 = fslc_getchar(); 15 | int l2 = fslc_getchar(); 16 | int o = fslc_getchar(); 17 | int ef = fslc_getchar(); 18 | 19 | CHECK_EQUAL('H', h); 20 | CHECK_EQUAL('e', e); 21 | CHECK_EQUAL('l', l1); 22 | CHECK_EQUAL('l', l2); 23 | CHECK_EQUAL('o', o); 24 | CHECK(ef < 0); 25 | } 26 | 27 | TEST_FIXTURE(StdIOFixture, FUnGetCTest) 28 | { 29 | istring.str("123"); 30 | 31 | int c1 = fslc_getc(&stream); 32 | int r1 = fslc_ungetc('a', &stream); 33 | int r2 = fslc_ungetc('b', &stream); 34 | int ca = fslc_getc(&stream); 35 | int c2 = fslc_getc(&stream); 36 | 37 | CHECK_EQUAL('1', c1); 38 | CHECK_EQUAL('a', r1); 39 | CHECK(r2 < 0); 40 | CHECK_EQUAL('a', ca); 41 | CHECK_EQUAL('2', c2); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /libc/src/fslc_memcpy.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | #include 3 | 4 | void *fslc_memcpy(void *dest, const void *src, size_t len) 5 | { 6 | /* Copy byte-by-byte up to word-aligned. 7 | * 8 | * There's a possibility, that src and dest have different offsets 9 | * to word boundary and can not both be used efficiently. 10 | * 11 | * In this case we use align to dest argument, because it then can be 12 | * written in one operation, instead of read-modify-write of 2 words. 13 | * 14 | * Most of the time both parameters should be word-aligned, however. 15 | */ 16 | unsigned char *b_src = (unsigned char *)src; 17 | unsigned char *b_dst = (unsigned char *)dest; 18 | for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; b_src++, b_dst++, len--) 19 | { 20 | *b_dst = *b_src; 21 | } 22 | 23 | /* Then all word-aligned */ 24 | unsigned long *w_src = (unsigned long*)b_src; 25 | unsigned long *w_dst = (unsigned long*)b_dst; 26 | for (;len >= sizeof(unsigned long); w_src++, w_dst++, len -= sizeof(unsigned long)) 27 | { 28 | *w_dst = *w_src; 29 | } 30 | 31 | /* And byte-by-byte the rest */ 32 | b_src = (unsigned char *)w_src; 33 | b_dst = (unsigned char *)w_dst; 34 | for (; len > 0; b_src++, b_dst++, len--) 35 | { 36 | *b_dst = *b_src; 37 | } 38 | 39 | return dest; 40 | } 41 | -------------------------------------------------------------------------------- /tests/strstr_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | SUITE(StrStr) 6 | { 7 | TEST(BasicTest) 8 | { 9 | const char *txt = "Test string"; 10 | 11 | const char *r = fslc_strstr(txt, "st"); 12 | const char *e = strstr(txt, "st"); 13 | 14 | CHECK_EQUAL((uintptr_t)e, (uintptr_t)r); 15 | } 16 | 17 | TEST(NotFoundTest) 18 | { 19 | const char *txt = "Test string"; 20 | 21 | const char *r = fslc_strstr(txt, "m"); 22 | const char *e = strstr(txt, "m"); 23 | 24 | CHECK_EQUAL((uintptr_t)e, (uintptr_t)r); // compare pointer values 25 | } 26 | 27 | TEST(FindSecond) 28 | { 29 | const char *txt = "Test text"; 30 | 31 | const char *r = fslc_strstr(txt, "te"); 32 | const char *e = strstr(txt, "te"); 33 | 34 | CHECK_EQUAL((uintptr_t)e, (uintptr_t)r); 35 | } 36 | 37 | TEST(FindSecondLongerTest) 38 | { 39 | const char *txt = "Test string"; 40 | 41 | const char *r = fslc_strstr(txt, "str"); 42 | const char *e = strstr(txt, "str"); 43 | 44 | CHECK_EQUAL((uintptr_t)e, (uintptr_t)r); 45 | } 46 | 47 | TEST(NotFoundAfter3) 48 | { 49 | const char *txt = "Test text"; 50 | 51 | const char *r = fslc_strstr(txt, "tu"); 52 | const char *e = strstr(txt, "tu"); 53 | 54 | CHECK_EQUAL((uintptr_t)e, (uintptr_t)r); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/stdio_fixture.h: -------------------------------------------------------------------------------- 1 | #ifndef STDIOFIXTURE_H 2 | #define STDIOFIXTURE_H 3 | 4 | #include "fslc_stdio.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct StdIOFixture 12 | { 13 | FSLC_FILE stream; 14 | 15 | enum struct CalledFunc { None, PreOp, PutC, PostOp }; 16 | 17 | struct FuncCallItem { 18 | enum CalledFunc opera; 19 | int param1; 20 | bool operator == (const FuncCallItem &other) const 21 | { 22 | return opera == other.opera 23 | && param1 == other.param1; 24 | } 25 | }; 26 | 27 | std::vector FuncCallLog; 28 | 29 | int eof_counter; 30 | std::ostringstream ostring; 31 | 32 | std::istringstream istring; 33 | 34 | int fail_getc_calls; 35 | 36 | std::unique_ptr expected_fstring; 37 | 38 | int eprintf(const char *format, ...); 39 | 40 | StdIOFixture(); 41 | 42 | static int fixture_putc(int c, FSLC_FILE *stream); 43 | static void fixture_preop(FSLC_FILE *stream); 44 | static void fixture_postop(FSLC_FILE *stream); 45 | static int fixture_getc(FSLC_FILE *stream); 46 | static int fail_getc(FSLC_FILE *stream); 47 | 48 | static int null_putc(int c, FSLC_FILE *stream); 49 | static void null_prepostop(FSLC_FILE *stream); 50 | }; 51 | 52 | 53 | std::ostream &operator<< (std::ostream &stream, const StdIOFixture::FuncCallItem &citem); 54 | 55 | 56 | #endif // STDIOFIXTURE_H 57 | -------------------------------------------------------------------------------- /tests/strncpy_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "strmod_fixture.h" 4 | #include 5 | 6 | SUITE(StrNCpy) 7 | { 8 | TEST_FIXTURE(StrModFixture, Copy0TerminateTest) 9 | { 10 | char *cc = fslc_strncpy(testString,"Hello, World!", 30); 11 | strncpy(expectedString,"Hello, World!", 30); 12 | 13 | CHECK_EQUAL((uintptr_t)testString, (uintptr_t)cc); 14 | 15 | CHECK_ARRAY_EQUAL(expectedString, testString, strlen(expectedString)+1); 16 | } 17 | 18 | TEST_FIXTURE(StrModFixture, CopyNTerminateTest) 19 | { 20 | char *cc = fslc_strncpy(testString,"Hello, World!", 5); 21 | strncpy(expectedString,"Hello, World!", 5); 22 | 23 | CHECK_EQUAL((uintptr_t)testString, (uintptr_t)cc); 24 | 25 | CHECK_ARRAY_EQUAL(expectedString, testString, MAXLEN); 26 | } 27 | 28 | TEST_FIXTURE(StrModFixture, CopyE0TerminateTest) 29 | { 30 | char *cc = fslc_strncpy_e(testString,"Hello, World!", 30); 31 | strncpy(expectedString,"Hello, World!", 30); 32 | 33 | CHECK_EQUAL((uintptr_t)testString+strlen(expectedString), (uintptr_t)cc); 34 | 35 | CHECK_ARRAY_EQUAL(expectedString, testString, strlen(expectedString)+1); 36 | } 37 | 38 | TEST_FIXTURE(StrModFixture, CopyENTerminateTest) 39 | { 40 | char *cc = fslc_strncpy_e(testString,"Hello, World!", 5); 41 | strncpy(expectedString,"Hello, World!", 5); 42 | 43 | CHECK_EQUAL((uintptr_t)testString+5, (uintptr_t)cc); 44 | 45 | CHECK_ARRAY_EQUAL(expectedString, testString, MAXLEN); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /libc/include/fslc/fslc_string.h: -------------------------------------------------------------------------------- 1 | #ifndef FSLC_STRING_H 2 | #define FSLC_STRING_H 3 | 4 | #include 5 | 6 | #ifndef ALT_FSLC_NAMES 7 | #define fslc_memset memset 8 | #define fslc_memcpy memcpy 9 | #define fslc_memmove memmove 10 | #define fslc_memcmp memcmp 11 | 12 | #define fslc_strlen strlen 13 | #define fslc_strcpy strcpy 14 | #define fslc_strncpy strncpy 15 | #define fslc_strcmp strcmp 16 | #define fslc_strncmp strncmp 17 | #define fslc_strchr strchr 18 | #define fslc_strstr strstr 19 | #define fslc_strpbrk strpbrk 20 | #define fslc_strspn strspn 21 | #define fslc_strtok_r strtok_r 22 | 23 | #endif /* ALT_FSLC_NAMES */ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif /* __cplusplus */ 28 | 29 | void *fslc_memset(void *ptr, int value, size_t num); 30 | void *fslc_memcpy(void *dest, const void *src, size_t len); 31 | void *fslc_memmove(void *dest, const void *src, size_t len); 32 | int fslc_memcmp(const void *ptr1, const void *ptr2, size_t num); 33 | 34 | size_t fslc_strlen(const char *str); 35 | char *fslc_strcpy(char *dest, const char *src); 36 | char *fslc_strncpy(char *dest, const char *src, size_t len); 37 | int fslc_strcmp(const char *str1, const char *str2); 38 | int fslc_strncmp(const char *str1, const char *str2, size_t num); 39 | char *fslc_strchr(const char *str, int c); 40 | char *fslc_strstr(const char *search_in, const char *search_for); 41 | char *fslc_strpbrk(const char *str, const char *delim); 42 | size_t fslc_strspn(const char *str, const char *delim); 43 | char *fslc_strtok_r(char *str, const char *delim, char **save_p); 44 | 45 | #ifdef __cplusplus 46 | } /* extern "C" */ 47 | #endif /* __cplusplus */ 48 | 49 | 50 | #endif /* FSLC_STRING_H */ 51 | -------------------------------------------------------------------------------- /tests/strcmp_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | #include "misc_utils.h" 6 | 7 | SUITE(StrCmp) 8 | { 9 | TEST(EqualTest) 10 | { 11 | const char *str1 = "Test string"; 12 | const char *str2 = "Test string"; 13 | 14 | int r = fslc_strcmp(str1, str2); 15 | int e = strcmp(str1, str2); 16 | 17 | CHECK_EQUAL(e, r); 18 | } 19 | 20 | TEST(LargerTest) 21 | { 22 | const char *str1 = "Test string 1"; 23 | const char *str2 = "Test string 2"; 24 | 25 | int r = fslc_strcmp(str1, str2); 26 | int e = strcmp(str1, str2); 27 | 28 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 29 | } 30 | 31 | TEST(SmallerTest) 32 | { 33 | const char *str1 = "Test string 1"; 34 | const char *str2 = "Test string 0"; 35 | 36 | int r = fslc_strcmp(str1, str2); 37 | int e = strcmp(str1, str2); 38 | 39 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 40 | } 41 | 42 | TEST(LongerTest) 43 | { 44 | const char *str1 = "Test string 1"; 45 | const char *str2 = "Test string"; 46 | 47 | int r = fslc_strcmp(str1, str2); 48 | int e = strcmp(str1, str2); 49 | 50 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 51 | } 52 | 53 | TEST(ShorterTest) 54 | { 55 | const char *str1 = "Test string"; 56 | const char *str2 = "Test string 2"; 57 | 58 | int r = fslc_strcmp(str1, str2); 59 | int e = strcmp(str1, str2); 60 | 61 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 62 | } 63 | 64 | TEST(NegTest) 65 | { 66 | const char *str1 = "Test string \xEF"; 67 | const char *str2 = "Test string 2"; 68 | 69 | int r = fslc_strcmp(str1, str2); 70 | int e = strcmp(str1, str2); 71 | 72 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /libc/include/fslc/fslc_stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef FSLC_STDIO_H 2 | #define FSLC_STDIO_H 3 | 4 | #include 5 | #include 6 | 7 | #ifndef ALT_FSLC_NAMES 8 | 9 | #define FSLC_FILE FILE 10 | #define fslc_stdout stdout 11 | #define fslc_stdin stdin 12 | #define fslc_putchar putchar 13 | #define fslc_fputc fputc 14 | #define fslc_fputs fputs 15 | #define fslc_puts puts 16 | 17 | #define fslc_vfprintf vfprintf 18 | #define fslc_vprintf vprintf 19 | #define fslc_fprintf fprintf 20 | #define fslc_printf printf 21 | 22 | #define fslc_fwrite fwrite 23 | #define fslc_fread fread 24 | 25 | #define fslc_getc getc 26 | #define fslc_getchar getchar 27 | #define fslc_ungetc ungetc 28 | #define fslc_fgets fgets 29 | 30 | #endif /* ALT_FSLC_NAMES */ 31 | 32 | typedef struct _FSLC_FILE FSLC_FILE; 33 | 34 | struct _FSLC_FILE 35 | { 36 | void *user_ptr; 37 | int (*putc)(int c, FSLC_FILE *stream); 38 | int (*getc)(FSLC_FILE *stream); 39 | void (*pre_output)(FSLC_FILE *stream); 40 | void (*post_output)(FSLC_FILE *stream); 41 | int ungetc_buf; 42 | }; 43 | 44 | extern FSLC_FILE *fslc_stdout; 45 | extern FSLC_FILE *fslc_stdin; 46 | 47 | #ifdef __cplusplus 48 | extern "C" { 49 | #endif /* __cplusplus */ 50 | 51 | int fslc_putchar(int c); 52 | int fslc_fputc(int c, FSLC_FILE *stream); 53 | int fslc_fputs(const char *str, FSLC_FILE *stream); 54 | int fslc_puts(const char *str); 55 | 56 | int fslc_vfprintf(FSLC_FILE *stream, const char *format, va_list arg); 57 | int fslc_vprintf(const char *format, va_list arg); 58 | int fslc_fprintf(FSLC_FILE *stream, const char *format, ...); 59 | int fslc_printf(const char *format, ...); 60 | 61 | size_t fslc_fwrite(const void *ptr, size_t size, size_t count, FSLC_FILE *stream); 62 | size_t fslc_fread(void *ptr, size_t size, size_t count, FSLC_FILE *stream); 63 | 64 | int fslc_getc(FSLC_FILE *stream); 65 | int fslc_getchar(void); 66 | int fslc_ungetc(int c, FSLC_FILE *stream); 67 | char *fslc_fgets(char *str, int num, FSLC_FILE *stream); 68 | 69 | #ifdef __cplusplus 70 | } /* extern "C" */ 71 | #endif /* __cplusplus */ 72 | 73 | 74 | #endif /* FSLC_STDIO_H */ 75 | -------------------------------------------------------------------------------- /libc/src/fslc_memmove.c: -------------------------------------------------------------------------------- 1 | #include "fslc_string.h" 2 | #include 3 | 4 | void *fslc_memmove(void *dest, const void *src, size_t len) 5 | { 6 | unsigned char *b_dst = (unsigned char *)dest; 7 | unsigned char *b_src = (unsigned char *)src; 8 | 9 | /* Need to check if memory regions overlaps. Then if the dest address is 10 | * larger than source, we need to copy backwards (or else source regions 11 | * ending will be overwritten by writes to dest, before they are read). 12 | * 13 | * In other cases it works identically as memcpy(). Same considerations 14 | * about address alignment applies here. 15 | */ 16 | if ( b_dst < b_src + len && b_dst > b_src) 17 | { 18 | b_src += len; 19 | b_dst += len; 20 | 21 | /* Byte-by-byte down to word-aligned. */ 22 | for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; ) 23 | { 24 | b_src--, b_dst--, len--; 25 | *b_dst = *b_src; 26 | } 27 | 28 | /* Then all word-aligned */ 29 | unsigned long *w_src = (unsigned long*)b_src; 30 | unsigned long *w_dst = (unsigned long*)b_dst; 31 | for (;len >= sizeof(unsigned long); ) 32 | { 33 | w_src--, w_dst--, len -= sizeof(unsigned long); 34 | *w_dst = *w_src; 35 | } 36 | 37 | /* And byte-by-byte the rest */ 38 | b_src = (unsigned char *)w_src; 39 | b_dst = (unsigned char *)w_dst; 40 | for (; len > 0; ) 41 | { 42 | b_src--, b_dst--, len--; 43 | *b_dst = *b_src; 44 | } 45 | } else { 46 | /* Byte-by-byte up to word-aligned. */ 47 | for (;((uintptr_t)b_dst & (sizeof(unsigned long)-1)) && len > 0; b_src++, b_dst++, len--) 48 | { 49 | *b_dst = *b_src; 50 | } 51 | 52 | /* Then all word-aligned */ 53 | unsigned long *w_src = (unsigned long *)b_src; 54 | unsigned long *w_dst = (unsigned long *)b_dst; 55 | for (;len >= sizeof(unsigned long); w_src++, w_dst++, len -= sizeof(unsigned long)) 56 | { 57 | *w_dst = *w_src; 58 | } 59 | 60 | /* And byte-by-byte the rest */ 61 | b_src = (unsigned char *)w_src; 62 | b_dst = (unsigned char *)w_dst; 63 | for (; len > 0; b_src++, b_dst++, len--) 64 | { 65 | *b_dst = *b_src; 66 | } 67 | } 68 | return dest; 69 | } 70 | -------------------------------------------------------------------------------- /tests/fread_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stdio_fixture.h" 4 | #include 5 | 6 | SUITE(FRead) 7 | { 8 | TEST_FIXTURE(StdIOFixture, FReadBasicTest) 9 | { 10 | uint32_t data[] = { 0x6ba09e07, 0x5f767b19, 0xb4a33cdd, 0x17a64c09, 0x92487695, 0x893092eb, 0 }; 11 | istring.str(std::string((const char *)data)); 12 | 13 | uint32_t data_read[6]; 14 | 15 | memset(data_read, 0, sizeof(data_read)); 16 | 17 | size_t rlen = fslc_fread(data_read, sizeof(uint32_t), 6, &stream); 18 | 19 | CHECK_EQUAL(6, rlen); 20 | 21 | CHECK_ARRAY_EQUAL(data, data_read, 6); 22 | } 23 | 24 | TEST_FIXTURE(StdIOFixture, FReadEofTest) 25 | { 26 | uint32_t data[] = { 0x6ba09e07, 0x5f767b19, 0xb4a33cdd, 0x17a64c09, 0x92487695, 0x890092eb }; 27 | istring.str(std::string((const char *)data)); 28 | 29 | uint32_t data_read[6]; 30 | 31 | memset(data_read, 0, sizeof(data_read)); 32 | 33 | size_t rlen = fslc_fread(data_read, sizeof(uint32_t), 6, &stream); 34 | 35 | CHECK_EQUAL(5, rlen); 36 | 37 | CHECK_ARRAY_EQUAL(data, data_read, 5); 38 | CHECK_EQUAL(data[5] & 0x0000FFFF, data_read[5]); 39 | } 40 | 41 | TEST_FIXTURE(StdIOFixture, FReadZeroCountTest) 42 | { 43 | uint32_t data_read[6]; 44 | uint32_t data_original[6]; 45 | 46 | stream.getc = fail_getc; 47 | 48 | memset(data_read, 0x20, sizeof(data_read)); 49 | memset(data_original, 0x20, sizeof(data_original)); 50 | 51 | size_t rlen = fslc_fread(data_read, sizeof(uint32_t), 0, &stream); 52 | 53 | CHECK_EQUAL(0, rlen); 54 | CHECK_EQUAL(0, fail_getc_calls); 55 | CHECK_ARRAY_EQUAL(data_original, data_read, 6); 56 | } 57 | 58 | TEST_FIXTURE(StdIOFixture, FReadZeroSizeTest) 59 | { 60 | uint32_t data_read[6]; 61 | uint32_t data_original[6]; 62 | 63 | stream.getc = fail_getc; 64 | 65 | memset(data_read, 0x20, sizeof(data_read)); 66 | memset(data_original, 0x20, sizeof(data_original)); 67 | 68 | size_t rlen = fslc_fread(data_read, 0, 6, &stream); 69 | 70 | CHECK_EQUAL(0, rlen); 71 | CHECK_EQUAL(0, fail_getc_calls); 72 | CHECK_ARRAY_EQUAL(data_original, data_read, 6); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4 | // 5 | // To add a test, simply put the following code in the a .cpp file of your choice: 6 | // 7 | // ================================= 8 | // Simple Test 9 | // ================================= 10 | // 11 | // TEST(YourTestName) 12 | // { 13 | // } 14 | // 15 | // The TEST macro contains enough machinery to turn this slightly odd-looking syntax into legal C++, and automatically register the test in a global list. 16 | // This test list forms the basis of what is executed by RunAllTests(). 17 | // 18 | // If you want to re-use a set of test data for more than one test, or provide setup/teardown for tests, 19 | // you can use the TEST_FIXTURE macro instead. The macro requires that you pass it a class name that it will instantiate, so any setup and teardown code should be in its constructor and destructor. 20 | // 21 | // struct SomeFixture 22 | // { 23 | // SomeFixture() { /* some setup */ } 24 | // ~SomeFixture() { /* some teardown */ } 25 | // 26 | // int testData; 27 | // }; 28 | // 29 | // TEST_FIXTURE(SomeFixture, YourTestName) 30 | // { 31 | // int temp = testData; 32 | // } 33 | // 34 | // ================================= 35 | // Test Suites 36 | // ================================= 37 | // 38 | // Tests can be grouped into suites, using the SUITE macro. A suite serves as a namespace for test names, so that the same test name can be used in two difference contexts. 39 | // 40 | // SUITE(YourSuiteName) 41 | // { 42 | // TEST(YourTestName) 43 | // { 44 | // } 45 | // 46 | // TEST(YourOtherTestName) 47 | // { 48 | // } 49 | // } 50 | // 51 | // This will place the tests into a C++ namespace called YourSuiteName, and make the suite name available to UnitTest++. 52 | // RunAllTests() can be called for a specific suite name, so you can use this to build named groups of tests to be run together. 53 | // Note how members of the fixture are used as if they are a part of the test, since the macro-generated test class derives from the provided fixture class. 54 | // 55 | // 56 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 57 | 58 | // run all tests 59 | int main(int argc, char **argv) 60 | { 61 | return UnitTest::RunAllTests(); 62 | } 63 | -------------------------------------------------------------------------------- /tests/stdio_fixture.cpp: -------------------------------------------------------------------------------- 1 | #include "stdio_fixture.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | StdIOFixture::StdIOFixture() 8 | { 9 | memset(&stream, 0, sizeof(FSLC_FILE)); 10 | stream.user_ptr = this; 11 | stream.putc = fixture_putc; 12 | stream.getc = fixture_getc; 13 | stream.ungetc_buf = -1; 14 | eof_counter = -1; // default value = forever 15 | fail_getc_calls = 0; 16 | } 17 | 18 | int StdIOFixture::fixture_putc(int c, FSLC_FILE *stream) 19 | { 20 | auto pf = (StdIOFixture *)stream->user_ptr; 21 | 22 | FuncCallItem call; 23 | 24 | call.opera = CalledFunc::PutC; 25 | call.param1 = c; 26 | 27 | pf->FuncCallLog.push_back(call); 28 | 29 | if (pf->eof_counter) 30 | { 31 | --pf->eof_counter; 32 | pf->ostring << (char)c; 33 | return c; 34 | } 35 | else 36 | return -1; 37 | } 38 | 39 | int StdIOFixture::fixture_getc(FSLC_FILE *stream) 40 | { 41 | auto pf = (StdIOFixture *)stream->user_ptr; 42 | 43 | return pf->istring.get(); 44 | } 45 | 46 | int StdIOFixture::fail_getc(FSLC_FILE *stream) 47 | { 48 | auto pf = (StdIOFixture *)stream->user_ptr; 49 | 50 | pf->fail_getc_calls++; 51 | } 52 | 53 | void StdIOFixture::fixture_preop(FSLC_FILE *stream) 54 | { 55 | auto pf = (StdIOFixture *)stream->user_ptr; 56 | 57 | FuncCallItem call; 58 | 59 | call.opera = CalledFunc::PreOp; 60 | call.param1 = 0; 61 | 62 | pf->FuncCallLog.push_back(call); 63 | } 64 | 65 | void StdIOFixture::fixture_postop(FSLC_FILE *stream) 66 | { 67 | auto pf = (StdIOFixture *)stream->user_ptr; 68 | 69 | FuncCallItem call; 70 | 71 | call.opera = CalledFunc::PostOp; 72 | call.param1 = 0; 73 | 74 | pf->FuncCallLog.push_back(call); 75 | } 76 | 77 | int StdIOFixture::null_putc(int c, FSLC_FILE *stream) 78 | { 79 | return c; 80 | } 81 | 82 | void StdIOFixture::null_prepostop(FSLC_FILE *stream) 83 | { 84 | } 85 | 86 | int StdIOFixture::eprintf(const char *format, ...) 87 | { 88 | va_list args; 89 | 90 | va_start(args, format); 91 | int len = vsnprintf(nullptr, 0, format, args); 92 | va_end(args); 93 | 94 | expected_fstring = std::unique_ptr(new char[len+1]); 95 | char *str = expected_fstring.get(); 96 | 97 | va_start(args, format); 98 | vsprintf(str, format, args); 99 | va_end(args); 100 | 101 | return len; 102 | } 103 | 104 | std::ostream &operator<< (std::ostream &stream, const StdIOFixture::FuncCallItem &citem) 105 | { 106 | stream << (int)citem.opera << "(" << citem.param1 << ")"; 107 | return stream; 108 | } 109 | -------------------------------------------------------------------------------- /tests/fgets_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stdio_fixture.h" 4 | #include 5 | 6 | SUITE(FGets) 7 | { 8 | TEST_FIXTURE(StdIOFixture, FGetsToEofTest) 9 | { 10 | istring.str("Hello"); 11 | 12 | char text_read[10]; 13 | 14 | char *str = fslc_fgets(text_read, 10, &stream); 15 | 16 | CHECK_EQUAL((uintptr_t)text_read, (uintptr_t)str); 17 | CHECK_EQUAL(0, str[5]); 18 | CHECK_EQUAL(5, strlen(str)); 19 | CHECK_EQUAL("Hello", std::string(str)); 20 | } 21 | 22 | TEST_FIXTURE(StdIOFixture, FGetsNewLineTest) 23 | { 24 | istring.str("Hello\nWorld"); 25 | 26 | char text_read[20]; 27 | 28 | char *str = fslc_fgets(text_read, 20, &stream); 29 | 30 | CHECK_EQUAL((uintptr_t)text_read, (uintptr_t)str); 31 | CHECK_EQUAL(0, str[6]); 32 | CHECK_EQUAL(6, strlen(str)); 33 | CHECK_EQUAL("Hello\n", std::string(str)); 34 | } 35 | 36 | TEST_FIXTURE(StdIOFixture, FGetsBufSizeTest) 37 | { 38 | istring.str("Hello_World"); 39 | 40 | char text_read[20]; 41 | 42 | char *str = fslc_fgets(text_read, 6, &stream); 43 | 44 | CHECK_EQUAL((uintptr_t)text_read, (uintptr_t)str); 45 | CHECK_EQUAL(0, str[5]); 46 | CHECK_EQUAL(5, strlen(str)); 47 | CHECK_EQUAL("Hello", std::string(str)); 48 | } 49 | 50 | TEST_FIXTURE(StdIOFixture, FGetsCrLfLineTest) 51 | { 52 | istring.str("Hello\r\nWorld"); 53 | 54 | char text_read[20]; 55 | 56 | char *str = fslc_fgets(text_read, 20, &stream); 57 | 58 | CHECK_EQUAL((uintptr_t)text_read, (uintptr_t)str); 59 | CHECK_EQUAL(0, str[7]); 60 | CHECK_EQUAL(7, strlen(str)); 61 | CHECK_EQUAL("Hello\r\n", std::string(str)); 62 | } 63 | 64 | TEST_FIXTURE(StdIOFixture, FGetsAfterNewLineTest) 65 | { 66 | istring.str("Hello\nWorld"); 67 | 68 | char text_read[20]; 69 | 70 | fslc_fgets(text_read, 20, &stream); 71 | char *str = fslc_fgets(text_read, 20, &stream); 72 | 73 | 74 | CHECK_EQUAL((uintptr_t)text_read, (uintptr_t)str); 75 | CHECK_EQUAL(0, str[5]); 76 | CHECK_EQUAL(5, strlen(str)); 77 | CHECK_EQUAL("World", std::string(str)); 78 | } 79 | 80 | TEST_FIXTURE(StdIOFixture, FGetsAfterCrLfLineTest) 81 | { 82 | istring.str("Hello\r\nWorld"); 83 | 84 | char text_read[20]; 85 | 86 | fslc_fgets(text_read, 20, &stream); 87 | char *str = fslc_fgets(text_read, 20, &stream); 88 | 89 | CHECK_EQUAL((uintptr_t)text_read, (uintptr_t)str); 90 | CHECK_EQUAL(0, str[5]); 91 | CHECK_EQUAL(5, strlen(str)); 92 | CHECK_EQUAL("World", std::string(str)); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/strtok_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "strmod_fixture.h" 4 | #include 5 | 6 | SUITE(StrTok) 7 | { 8 | TEST_FIXTURE(StrModFixture, BasicParseTest) 9 | { 10 | strcpy(testString, "Delimited,string;by.some-chars"); 11 | strcpy(expectedString, "Delimited,string;by.some-chars"); 12 | 13 | char *rsave, *esave; 14 | 15 | char *r1 = fslc_strtok_r(testString, "-.;,", &rsave); 16 | char *e1 = strtok_r(expectedString, "-.;,", &esave); 17 | 18 | CHECK_EQUAL(e1, r1); // compare strings 19 | CHECK_EQUAL(e1 - expectedString, r1 - testString); // compare offsets 20 | 21 | char *r2 = fslc_strtok_r(NULL, "-.;,", &rsave); 22 | char *e2 = strtok_r(NULL, "-.;,", &esave); 23 | 24 | CHECK_EQUAL(e2, r2); // compare strings 25 | CHECK_EQUAL(e2 - expectedString, r2 - testString); // compare offsets 26 | 27 | CHECK_ARRAY_EQUAL(expectedString, testString, MAXLEN); 28 | } 29 | 30 | TEST_FIXTURE(StrModFixture, NotFoundTest) 31 | { 32 | strcpy(testString, "Delimited,string;by.some-chars"); 33 | strcpy(expectedString, "Delimited,string;by.some-chars"); 34 | 35 | char *rsave, *esave; 36 | 37 | char *r1 = fslc_strtok_r(testString, "!@#", &rsave); 38 | char *e1 = strtok_r(expectedString, "!@#", &esave); 39 | 40 | CHECK_EQUAL(e1, r1); // compare strings 41 | CHECK_EQUAL(e1 - expectedString, r1 - testString); // compare offsets 42 | 43 | char *r2 = fslc_strtok_r(NULL, "!@#", &rsave); 44 | 45 | CHECK_EQUAL(NULL, (uintptr_t)r2); 46 | 47 | CHECK_ARRAY_EQUAL(expectedString, testString, MAXLEN); 48 | 49 | char *r3 = fslc_strtok_r(NULL, "!@#", &rsave); 50 | 51 | CHECK_EQUAL(NULL, (uintptr_t)r3); 52 | } 53 | 54 | TEST_FIXTURE(StrModFixture, MultipleSepTest) 55 | { 56 | strcpy(testString, "/this/is//file/path/"); 57 | strcpy(expectedString, "/this/is//file/path/"); 58 | 59 | char *rsave, *esave; 60 | 61 | char *r1 = fslc_strtok_r(testString, "/", &rsave); 62 | char *e1 = strtok_r(expectedString, "/", &esave); 63 | 64 | CHECK_EQUAL(e1, r1); // compare strings 65 | CHECK_EQUAL(e1 - expectedString, r1 - testString); // compare offsets 66 | 67 | char *r2 = fslc_strtok_r(NULL, "/", &rsave); 68 | char *e2 = strtok_r(NULL, "/", &esave); 69 | 70 | CHECK_EQUAL(e2, r2); // compare strings 71 | CHECK_EQUAL(e2 - expectedString, r2 - testString); // compare offsets 72 | 73 | char *r3 = fslc_strtok_r(NULL, "/", &rsave); 74 | char *e3 = strtok_r(NULL, "/", &esave); 75 | 76 | CHECK_EQUAL(e3, r3); // compare strings 77 | CHECK_EQUAL(e3 - expectedString, r3 - testString); // compare offsets 78 | 79 | char *r4 = fslc_strtok_r(NULL, "/", &rsave); 80 | char *e4 = strtok_r(NULL, "/", &esave); 81 | 82 | CHECK_EQUAL(e4, r4); // compare strings 83 | CHECK_EQUAL(e4 - expectedString, r4 - testString); // compare offsets 84 | 85 | char *r5 = fslc_strtok_r(NULL, "/", &rsave); 86 | char *e5 = strtok_r(NULL, "/", &esave); 87 | 88 | CHECK_EQUAL((uintptr_t)e5, (uintptr_t)r5); // compare pointers (should be NULL) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/strncmp_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | #include "misc_utils.h" 6 | 7 | SUITE(StrNCmp) 8 | { 9 | TEST(Equal0Test) 10 | { 11 | const char *str1 = "Test string"; 12 | const char *str2 = "Test string"; 13 | 14 | int r = fslc_strncmp(str1, str2, 20); 15 | int e = strncmp(str1, str2, 20); 16 | 17 | CHECK_EQUAL(e, r); 18 | } 19 | 20 | TEST(EqualNTest) 21 | { 22 | const char *str1 = "Test string"; 23 | const char *str2 = "Test text"; 24 | 25 | int r = fslc_strncmp(str1, str2, 5); 26 | int e = strncmp(str1, str2, 5); 27 | 28 | CHECK_EQUAL(e, r); 29 | } 30 | 31 | TEST(Larger0Test) 32 | { 33 | const char *str1 = "Test string 1"; 34 | const char *str2 = "Test string 2"; 35 | 36 | int r = fslc_strncmp(str1, str2, 20); 37 | int e = strncmp(str1, str2, 20); 38 | 39 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 40 | } 41 | 42 | TEST(LargerNTest) 43 | { 44 | const char *str1 = "Test 1 string"; 45 | const char *str2 = "Test 2 string"; 46 | 47 | int r = fslc_strncmp(str1, str2, 6); 48 | int e = strncmp(str1, str2, 6); 49 | 50 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 51 | } 52 | 53 | TEST(Smaller0Test) 54 | { 55 | const char *str1 = "Test string 1"; 56 | const char *str2 = "Test string 0"; 57 | 58 | int r = fslc_strncmp(str1, str2, 20); 59 | int e = strncmp(str1, str2, 20); 60 | 61 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 62 | } 63 | 64 | TEST(SmallerNTest) 65 | { 66 | const char *str1 = "Test 1 string"; 67 | const char *str2 = "Test 0 string"; 68 | 69 | int r = fslc_strncmp(str1, str2, 6); 70 | int e = strncmp(str1, str2, 6); 71 | 72 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 73 | } 74 | 75 | TEST(Longer0Test) 76 | { 77 | const char *str1 = "Test string 1"; 78 | const char *str2 = "Test string"; 79 | 80 | int r = fslc_strncmp(str1, str2, 20); 81 | int e = strncmp(str1, str2, 20); 82 | 83 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 84 | } 85 | 86 | TEST(NotLongerNTest) 87 | { 88 | const char *str1 = "Test string 1"; 89 | const char *str2 = "Test string"; 90 | 91 | int r = fslc_strncmp(str1, str2, 11); 92 | int e = strncmp(str1, str2, 11); 93 | 94 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 95 | } 96 | 97 | TEST(Shorter0Test) 98 | { 99 | const char *str1 = "Test string"; 100 | const char *str2 = "Test string 2"; 101 | 102 | int r = fslc_strncmp(str1, str2, 20); 103 | int e = strncmp(str1, str2, 20); 104 | 105 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 106 | } 107 | 108 | TEST(NotShorterNTest) 109 | { 110 | const char *str1 = "Test string"; 111 | const char *str2 = "Test string 2"; 112 | 113 | int r = fslc_strncmp(str1, str2, 11); 114 | int e = strncmp(str1, str2, 11); 115 | 116 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 117 | } 118 | 119 | TEST(Neg0Test) 120 | { 121 | const char *str1 = "Test string \xEF"; 122 | const char *str2 = "Test string 2"; 123 | 124 | int r = fslc_strncmp(str1, str2, 20); 125 | int e = strncmp(str1, str2, 20); 126 | 127 | CHECK_EQUAL(SIGNOF(e) , SIGNOF(r)); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /tests/memmove_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | /** Test fixture containing pre-seeded memory regions. 6 | * 7 | * testArray - should be modified by tested function - fslc_memmove(), 8 | * expected - by reference implementation - host system's memmove(). 9 | * 10 | * Modified regions should be compared afterwards. 11 | */ 12 | struct MemmoveFixture 13 | { 14 | static const int TESTARRAY_SIZE = 48; 15 | 16 | char testArray[TESTARRAY_SIZE]; 17 | char expected[TESTARRAY_SIZE]; 18 | 19 | MemmoveFixture() 20 | { 21 | for (int i = 0; i < TESTARRAY_SIZE; ++i) 22 | { 23 | testArray[i] = i+'A'; 24 | expected[i] = testArray[i]; 25 | } 26 | } 27 | }; 28 | 29 | SUITE(MemMove) 30 | { 31 | TEST_FIXTURE(MemmoveFixture, MoveAligned8BytesNonOverlap) 32 | { 33 | void *r = fslc_memmove(testArray+24, testArray+8, 16); 34 | memmove(expected+24, expected+8, 16); 35 | 36 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 37 | CHECK_EQUAL(testArray+24, r); 38 | } 39 | 40 | TEST_FIXTURE(MemmoveFixture, MoveAligned16BytesOverlapForward) 41 | { 42 | void *r = fslc_memmove(testArray+16, testArray+8, 16); 43 | memmove(expected+16, expected+8, 16); 44 | 45 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 46 | CHECK_EQUAL(testArray+16, r); 47 | } 48 | 49 | TEST_FIXTURE(MemmoveFixture, MoveAligned16BytesOverlapBackward) 50 | { 51 | void *r = fslc_memmove(testArray+8, testArray+16, 16); 52 | memmove(expected+8, expected+16, 16); 53 | 54 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 55 | CHECK_EQUAL(testArray+8, r); 56 | } 57 | 58 | 59 | TEST_FIXTURE(MemmoveFixture, MoveNonAligned13BytesNonOverlap) 60 | { 61 | void *r = fslc_memmove(testArray+22, testArray+7, 13); 62 | memmove(expected+22, expected+7, 13); 63 | 64 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 65 | CHECK_EQUAL(testArray+22, r); 66 | } 67 | 68 | TEST_FIXTURE(MemmoveFixture, MoveNonAligned19BytesOverlapForward) 69 | { 70 | void *r = fslc_memmove(testArray+14, testArray+6, 19); 71 | memmove(expected+14, expected+6, 19); 72 | 73 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 74 | CHECK_EQUAL(testArray+14, r); 75 | } 76 | 77 | TEST_FIXTURE(MemmoveFixture, MoveNonAligned19BytesOverlapBackward) 78 | { 79 | void *r = fslc_memmove(testArray+6, testArray+14, 19); 80 | memmove(expected+6, expected+14, 19); 81 | 82 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 83 | CHECK_EQUAL(testArray+6, r); 84 | } 85 | 86 | TEST_FIXTURE(MemmoveFixture, MoveNonAligned1ByteNonOverlap) 87 | { 88 | void *r = fslc_memmove(testArray+22, testArray+7, 1); 89 | memmove(expected+22, expected+7, 1); 90 | 91 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 92 | CHECK_EQUAL(testArray+22, r); 93 | } 94 | 95 | TEST_FIXTURE(MemmoveFixture, MoveNonAligned2BytesOverlapBackward) 96 | { 97 | void *r = fslc_memmove(testArray+9, testArray+8, 2); 98 | memmove(expected+9, expected+8, 2); 99 | 100 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 101 | CHECK_EQUAL(testArray+9, r); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tests/putc_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stdio_fixture.h" 4 | 5 | SUITE(PutC) 6 | { 7 | TEST_FIXTURE(StdIOFixture, BasicFPutCTest) 8 | { 9 | int r = fslc_fputc('A', &stream); 10 | 11 | FuncCallItem expected[] = { { CalledFunc::PutC, 'A' } }; 12 | 13 | CHECK_EQUAL('A', r); 14 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 15 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 16 | CHECK_EQUAL("A", ostring.str()); 17 | } 18 | 19 | TEST_FIXTURE(StdIOFixture, BasicPutCharTest) 20 | { 21 | fslc_stdout = &stream; 22 | 23 | int r = fslc_putchar('B'); 24 | 25 | FuncCallItem expected[] = { { CalledFunc::PutC, 'B' } }; 26 | 27 | CHECK_EQUAL('B', r); 28 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 29 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 30 | CHECK_EQUAL("B", ostring.str()); 31 | } 32 | 33 | TEST_FIXTURE(StdIOFixture, PreOpFPutCTest) 34 | { 35 | stream.pre_output = fixture_preop; 36 | int r = fslc_fputc('C', &stream); 37 | 38 | FuncCallItem expected[] = { { CalledFunc::PreOp, 0 }, { CalledFunc::PutC, 'C' } }; 39 | 40 | CHECK_EQUAL('C', r); 41 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 42 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 43 | CHECK_EQUAL("C", ostring.str()); 44 | } 45 | 46 | TEST_FIXTURE(StdIOFixture, PostpFPutCTest) 47 | { 48 | stream.post_output = fixture_postop; 49 | int r = fslc_fputc('D', &stream); 50 | 51 | FuncCallItem expected[] = { { CalledFunc::PutC, 'D' }, { CalledFunc::PostOp, 0 } }; 52 | 53 | CHECK_EQUAL('D', r); 54 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 55 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 56 | CHECK_EQUAL("D", ostring.str()); 57 | } 58 | 59 | TEST_FIXTURE(StdIOFixture, PrePostOpFPutCTest) 60 | { 61 | stream.pre_output = fixture_preop; 62 | stream.post_output = fixture_postop; 63 | int r = fslc_fputc('E', &stream); 64 | 65 | FuncCallItem expected[] = { { CalledFunc::PreOp, 0 }, { CalledFunc::PutC, 'E' }, { CalledFunc::PostOp, 0 } }; 66 | 67 | CHECK_EQUAL('E', r); 68 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 69 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 70 | CHECK_EQUAL("E", ostring.str()); 71 | } 72 | 73 | TEST_FIXTURE(StdIOFixture, EofFPutCTest) 74 | { 75 | eof_counter = 0; 76 | int r = fslc_fputc('A', &stream); 77 | 78 | FuncCallItem expected[] = { { CalledFunc::PutC, 'A' } }; 79 | 80 | CHECK(r < 0); 81 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 82 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 83 | CHECK_EQUAL("", ostring.str()); 84 | } 85 | 86 | TEST_FIXTURE(StdIOFixture, EofPrePostOpFPutCTest) 87 | { 88 | eof_counter = 0; 89 | stream.pre_output = fixture_preop; 90 | stream.post_output = fixture_postop; 91 | int r = fslc_fputc('E', &stream); 92 | 93 | FuncCallItem expected[] = { { CalledFunc::PreOp, 0 }, { CalledFunc::PutC, 'E' }, { CalledFunc::PostOp, 0 } }; 94 | 95 | CHECK(r < 0); 96 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 97 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 98 | CHECK_EQUAL("", ostring.str()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tests/memcmp_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | #include "misc_utils.h" 6 | 7 | SUITE(MemCmp) 8 | { 9 | TEST(CmpAligned8BytesEqual) 10 | { 11 | char arr1[] = "12345678"; 12 | char arr2[] = "12345678"; 13 | 14 | int cmp_res = fslc_memcmp(arr1, arr2, 8); 15 | int cmp_exp = memcmp(arr1, arr2, 8); 16 | 17 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 18 | } 19 | 20 | TEST(CmpAligned8BytesGt) 21 | { 22 | char arr1[] = "12345678"; 23 | char arr2[] = "12335678"; 24 | 25 | int cmp_res = fslc_memcmp(arr1, arr2, 8); 26 | int cmp_exp = memcmp(arr1, arr2, 8); 27 | 28 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 29 | } 30 | 31 | TEST(CmpUnAlignedBeginning19BytesLt) 32 | { 33 | char arr1[] = "12335678901234567890"; 34 | char arr2[] = "12345678901234567890"; 35 | 36 | int cmp_res = fslc_memcmp(arr1+1, arr2+1, 19); 37 | int cmp_exp = memcmp(arr1+1, arr2+1, 19); 38 | 39 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 40 | } 41 | 42 | TEST(CmpUnAlignedBeginning2BytesEq) 43 | { 44 | char arr1[] = "123"; 45 | char arr2[] = "123"; 46 | 47 | int cmp_res = fslc_memcmp(arr1+1, arr2+1, 2); 48 | int cmp_exp = memcmp(arr1+1, arr2+1, 2); 49 | 50 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 51 | } 52 | 53 | TEST(CmpUnAlignedEnd19BytesLt) 54 | { 55 | char arr1[] = "12345678901234567790"; 56 | char arr2[] = "12345678901234567890"; 57 | 58 | int cmp_res = fslc_memcmp(arr1+1, arr2+1, 19); 59 | int cmp_exp = memcmp(arr1+1, arr2+1, 19); 60 | 61 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 62 | } 63 | 64 | TEST(CmpUnAlignedEnd19BytesGt) 65 | { 66 | char arr1[] = "12345678901234567990"; 67 | char arr2[] = "12345678901234567890"; 68 | 69 | int cmp_res = fslc_memcmp(arr1+1, arr2+1, 19); 70 | int cmp_exp = memcmp(arr1+1, arr2+1, 19); 71 | 72 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 73 | } 74 | 75 | TEST(CmpLongLongNegAlignedGt) 76 | { 77 | unsigned long long arr1[] = {0xBADABAFAEACEBCDFULL}; 78 | unsigned long long arr2[] = {0x0000000000000000ULL}; 79 | 80 | int cmp_res = fslc_memcmp(arr1, arr2, sizeof(arr1)); 81 | int cmp_exp = memcmp(arr1, arr2, sizeof(arr1)); 82 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 83 | } 84 | 85 | TEST(CmpLongLongNegUnAlignedGt) 86 | { 87 | unsigned long long arr1[] = {0xBADABAFAEACEBCDFULL}; 88 | unsigned long long arr2[] = {0x0000000000000000ULL}; 89 | 90 | int cmp_res = fslc_memcmp((void *)(((uintptr_t)arr1)+1), (void *)(((uintptr_t)arr2)+1), sizeof(arr1)-1); 91 | int cmp_exp = memcmp((void *)(((uintptr_t)arr1)+1), (void *)(((uintptr_t)arr2)+1), sizeof(arr1)-1); 92 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 93 | } 94 | 95 | TEST(CmpLongLongNegAlignedLt) 96 | { 97 | unsigned long long arr1[] = {0x0000000000000000ULL}; 98 | unsigned long long arr2[] = {0xBADABAFAEACEBCDFULL}; 99 | 100 | int cmp_res = fslc_memcmp(arr1, arr2, sizeof(arr1)); 101 | int cmp_exp = memcmp(arr1, arr2, sizeof(arr1)); 102 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 103 | } 104 | 105 | TEST(CmpLongLongNegUnAlignedLt) 106 | { 107 | unsigned long long arr1[] = {0x0000000000000000ULL}; 108 | unsigned long long arr2[] = {0xBADABAFAEACEBCDFULL}; 109 | 110 | int cmp_res = fslc_memcmp((void *)(((uintptr_t)arr1)+1), (void *)(((uintptr_t)arr2)+1), sizeof(arr1)-1); 111 | int cmp_exp = memcmp((void *)(((uintptr_t)arr1)+1), (void *)(((uintptr_t)arr2)+1), sizeof(arr1)-1); 112 | CHECK_EQUAL(SIGNOF(cmp_exp), SIGNOF(cmp_res)); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /tests/fwrite_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stdio_fixture.h" 4 | 5 | SUITE(FWrite) 6 | { 7 | TEST_FIXTURE(StdIOFixture, FWriteBasicTest) 8 | { 9 | uint32_t data[] = { 0x6ba09e07, 0x5f767b19, 0xb4a33cdd, 0x17a64c09, 0x92487695, 0x853092eb }; 10 | 11 | int r = fslc_fwrite(data, sizeof(uint32_t), 6, &stream); 12 | 13 | CHECK_EQUAL(sizeof(data)/sizeof(uint32_t), r); 14 | 15 | std::vector expected_calls; 16 | unsigned char *c = (unsigned char *)data; 17 | for (int i = 0; i < sizeof(data); ++i) 18 | expected_calls.push_back({ CalledFunc::PutC, c[i] }); 19 | 20 | CHECK_EQUAL(expected_calls.size(), FuncCallLog.size()); 21 | CHECK_ARRAY_EQUAL(expected_calls, FuncCallLog, FuncCallLog.size()); 22 | } 23 | 24 | TEST_FIXTURE(StdIOFixture, FWritePrePostTest) 25 | { 26 | uint32_t data[] = { 0x6ba09e07, 0x5f767b19, 0xb4a33cdd, 0x17a64c09, 0x92487695, 0x853092eb }; 27 | 28 | stream.pre_output = fixture_preop; 29 | stream.post_output = fixture_postop; 30 | 31 | int r = fslc_fwrite(data, sizeof(uint32_t), 6, &stream); 32 | 33 | CHECK_EQUAL(sizeof(data)/sizeof(uint32_t), r); 34 | 35 | std::vector expected_calls; 36 | expected_calls.push_back({ CalledFunc::PreOp, 0 }); 37 | unsigned char *c = (unsigned char *)data; 38 | for (int i = 0; i < sizeof(data); ++i) 39 | expected_calls.push_back({ CalledFunc::PutC, c[i] }); 40 | expected_calls.push_back({ CalledFunc::PostOp, 0 }); 41 | 42 | CHECK_EQUAL(expected_calls.size(), FuncCallLog.size()); 43 | CHECK_ARRAY_EQUAL(expected_calls, FuncCallLog, FuncCallLog.size()); 44 | } 45 | 46 | TEST_FIXTURE(StdIOFixture, FWriteZeroSizeTest) 47 | { 48 | stream.pre_output = fixture_preop; 49 | stream.post_output = fixture_postop; 50 | 51 | int r = fslc_fwrite(nullptr, 0, 6, &stream); 52 | 53 | CHECK_EQUAL(0, r); 54 | 55 | std::vector expected_calls; 56 | expected_calls.push_back({ CalledFunc::PreOp, 0 }); 57 | expected_calls.push_back({ CalledFunc::PostOp, 0 }); 58 | 59 | CHECK_EQUAL(expected_calls.size(), FuncCallLog.size()); 60 | CHECK_ARRAY_EQUAL(expected_calls, FuncCallLog, FuncCallLog.size()); 61 | } 62 | 63 | TEST_FIXTURE(StdIOFixture, FWriteZeroCountTest) 64 | { 65 | stream.pre_output = fixture_preop; 66 | stream.post_output = fixture_postop; 67 | 68 | int r = fslc_fwrite(nullptr, sizeof(uint32_t), 0, &stream); 69 | 70 | CHECK_EQUAL(0, r); 71 | 72 | std::vector expected_calls; 73 | expected_calls.push_back({ CalledFunc::PreOp, 0 }); 74 | expected_calls.push_back({ CalledFunc::PostOp, 0 }); 75 | 76 | CHECK_EQUAL(expected_calls.size(), FuncCallLog.size()); 77 | CHECK_ARRAY_EQUAL(expected_calls, FuncCallLog, FuncCallLog.size()); 78 | } 79 | 80 | TEST_FIXTURE(StdIOFixture, FWriteEOFTest) 81 | { 82 | uint32_t data[] = { 0x6ba09e07, 0x5f767b19, 0xb4a33cdd, 0x17a64c09, 0x92487695, 0x853092eb }; 83 | 84 | stream.pre_output = fixture_preop; 85 | stream.post_output = fixture_postop; 86 | 87 | const int num_eof = 18; 88 | 89 | eof_counter = num_eof; 90 | 91 | int r = fslc_fwrite(data, sizeof(uint32_t), 6, &stream); 92 | 93 | CHECK_EQUAL(num_eof/sizeof(uint32_t), r); 94 | 95 | std::vector expected_calls; 96 | expected_calls.push_back({ CalledFunc::PreOp, 0 }); 97 | unsigned char *c = (unsigned char *)data; 98 | for (int i = 0; i <= num_eof; ++i) 99 | expected_calls.push_back({ CalledFunc::PutC, c[i] }); 100 | expected_calls.push_back({ CalledFunc::PostOp, 0 }); 101 | 102 | CHECK_EQUAL(expected_calls.size(), FuncCallLog.size()); 103 | CHECK_ARRAY_EQUAL(expected_calls, FuncCallLog, FuncCallLog.size()); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tests/memcpy_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include 4 | 5 | /** Test fixture containing pre-seeded memory regions. 6 | * 7 | * sourceArray - source memory should be copied from, 8 | * testArray - should be modified by tested function - fslc_memcpy(), 9 | * expected - by reference implementation - host system's memcpy(). 10 | * 11 | * Modified regions should be compared afterwards. 12 | */ 13 | struct MemcpyFixture 14 | { 15 | static const int TESTARRAY_SIZE = 24; 16 | 17 | char sourceArray[TESTARRAY_SIZE]; 18 | char testArray[TESTARRAY_SIZE]; 19 | char expected[TESTARRAY_SIZE]; 20 | 21 | MemcpyFixture() 22 | { 23 | for (int i = 0; i < TESTARRAY_SIZE; ++i) 24 | { 25 | sourceArray[i] = i+'a'; 26 | testArray[i] = i+'A'; 27 | expected[i] = testArray[i]; 28 | } 29 | } 30 | }; 31 | 32 | SUITE(MemCpy) 33 | { 34 | TEST_FIXTURE(MemcpyFixture, CopyAligned8Bytes) 35 | { 36 | void *r = fslc_memcpy(testArray+8, sourceArray+8, 8); 37 | memcpy(expected+8, sourceArray+8, 8); 38 | 39 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 40 | CHECK_EQUAL(testArray+8, r); 41 | } 42 | 43 | TEST_FIXTURE(MemcpyFixture, CopyOffset1Negative8Bytes) 44 | { 45 | void *r = fslc_memcpy(testArray+7, sourceArray+7, 8); 46 | memcpy(expected+7, sourceArray+7, 8); 47 | 48 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 49 | CHECK_EQUAL(testArray+7, r); 50 | } 51 | 52 | TEST_FIXTURE(MemcpyFixture, CopyOffset1Positive8Bytes) 53 | { 54 | void *r = fslc_memcpy(testArray+9, sourceArray+9, 8); 55 | memcpy(expected+9, sourceArray+9, 8); 56 | 57 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 58 | CHECK_EQUAL(testArray+9, r); 59 | } 60 | 61 | TEST_FIXTURE(MemcpyFixture, CopyOffset1Both10Bytes) 62 | { 63 | void *r = fslc_memcpy(testArray+7, sourceArray+7, 10); 64 | memcpy(expected+7, sourceArray+7, 10); 65 | 66 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 67 | CHECK_EQUAL(testArray+7, r); 68 | } 69 | 70 | TEST_FIXTURE(MemcpyFixture, CopyOffset1Both6Bytes) 71 | { 72 | void *r = fslc_memcpy(testArray+9, sourceArray+9, 6); 73 | memcpy(expected+9, sourceArray+9, 6); 74 | 75 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 76 | CHECK_EQUAL(testArray+9, r); 77 | } 78 | 79 | TEST_FIXTURE(MemcpyFixture, CopyOffset2and1Negative8Bytes) 80 | { 81 | void *r = fslc_memcpy(testArray+6, sourceArray+7, 8); 82 | memcpy(expected+6, sourceArray+7, 8); 83 | 84 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 85 | CHECK_EQUAL(testArray+6, r); 86 | } 87 | 88 | TEST_FIXTURE(MemcpyFixture, CopyOffset2and1Positive8Bytes) 89 | { 90 | void *r = fslc_memcpy(testArray+10, sourceArray+9, 8); 91 | memcpy(expected+10, sourceArray+9, 8); 92 | 93 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 94 | CHECK_EQUAL(testArray+10, r); 95 | } 96 | 97 | TEST_FIXTURE(MemcpyFixture, CopyOffset2and1Both10Bytes) 98 | { 99 | void *r = fslc_memcpy(testArray+6, sourceArray+7, 10); 100 | memcpy(expected+6, sourceArray+7, 10); 101 | 102 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 103 | CHECK_EQUAL(testArray+6, r); 104 | } 105 | 106 | TEST_FIXTURE(MemcpyFixture, CopyOffset2and1Both6Bytes) 107 | { 108 | void *r = fslc_memcpy(testArray+10, sourceArray+9, 6); 109 | memcpy(expected+10, sourceArray+9, 6); 110 | 111 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 112 | CHECK_EQUAL(testArray+10, r); 113 | } 114 | 115 | TEST_FIXTURE(MemcpyFixture, CopyOffset2and1Both1Byte) 116 | { 117 | void *r = fslc_memcpy(testArray+10, sourceArray+9, 1); 118 | memcpy(expected+10, sourceArray+9, 1); 119 | 120 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 121 | CHECK_EQUAL(testArray+10, r); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /tests/memset_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_string.h" 3 | #include "stringx.h" 4 | #include 5 | 6 | /** Test fixture containing 2 identically pre-seeded memory regions. 7 | * 8 | * One of them should be modified by tested function - fslc_memset(), 9 | * another - by reference implementation - host system's memset(). 10 | * 11 | * Modified regions should be compared afterwards. 12 | */ 13 | struct MemsetFixture 14 | { 15 | static const int TESTARRAY_SIZE = 24; 16 | 17 | char testArray[TESTARRAY_SIZE]; 18 | char expected[TESTARRAY_SIZE]; 19 | 20 | MemsetFixture() 21 | { 22 | for (int i = 0; i < TESTARRAY_SIZE; ++i) 23 | { 24 | testArray[i] = i+'A'; 25 | expected[i] = testArray[i]; 26 | } 27 | } 28 | }; 29 | 30 | 31 | SUITE(MemSet) 32 | { 33 | TEST_FIXTURE(MemsetFixture, SetZeroAligned8Bytes) 34 | { 35 | void *r = fslc_memset(testArray+8, 0, 8); 36 | memset(expected+8, 0, 8); 37 | 38 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 39 | CHECK_EQUAL(testArray+8, r); 40 | } 41 | 42 | TEST_FIXTURE(MemsetFixture, SetZeroOffset1Negative8Bytes) 43 | { 44 | void *r = fslc_memset(testArray+7, 0, 8); 45 | memset(expected+7, 0, 8); 46 | 47 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 48 | CHECK_EQUAL(testArray+7, r); 49 | } 50 | 51 | TEST_FIXTURE(MemsetFixture, SetZeroOffset1Positive8Bytes) 52 | { 53 | void *r = fslc_memset(testArray+9, 0, 8); 54 | memset(expected+9, 0, 8); 55 | 56 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 57 | CHECK_EQUAL(testArray+9, r); 58 | } 59 | 60 | TEST_FIXTURE(MemsetFixture, SetZeroOffset1Both10Bytes) 61 | { 62 | void *r = fslc_memset(testArray+7, 0, 10); 63 | memset(expected+7, 0, 10); 64 | 65 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 66 | CHECK_EQUAL(testArray+7, r); 67 | } 68 | 69 | TEST_FIXTURE(MemsetFixture, SetZeroOffset1Both6Bytes) 70 | { 71 | void *r = fslc_memset(testArray+9, 0, 6); 72 | memset(expected+9, 0, 6); 73 | 74 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 75 | CHECK_EQUAL(testArray+9, r); 76 | } 77 | 78 | TEST_FIXTURE(MemsetFixture, SetZeroOffset1Both1Byte) 79 | { 80 | void *r = fslc_memset(testArray+9, 0, 1); 81 | memset(expected+9, 0, 1); 82 | 83 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 84 | CHECK_EQUAL(testArray+9, r); 85 | } 86 | 87 | TEST_FIXTURE(MemsetFixture, Set42Aligned8Bytes) 88 | { 89 | void *r = fslc_memset(testArray+8, 42, 8); 90 | memset(expected+8, 42, 8); 91 | 92 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 93 | CHECK_EQUAL(testArray+8, r); 94 | } 95 | 96 | TEST_FIXTURE(MemsetFixture, SetMultiByteAligned8Bytes) 97 | { 98 | void *r = fslc_memset(testArray+8, 0x4266, 8); 99 | memset(expected+8, 0x4266, 8); 100 | 101 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 102 | CHECK_EQUAL(testArray+8, r); 103 | } 104 | 105 | TEST_FIXTURE(MemsetFixture, SetMultiByteOffset1Both10Bytes) 106 | { 107 | void *r = fslc_memset(testArray+7, 0x4266, 10); 108 | memset(expected+7, 0x4266, 10); 109 | 110 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 111 | CHECK_EQUAL(testArray+7, r); 112 | } 113 | 114 | TEST_FIXTURE(MemsetFixture, SetLDiffBytes) 115 | { 116 | #if __SIZEOF_LONG__ == 4 117 | unsigned long val = 0xCAFEBABE; 118 | unsigned char setVal[] = { 0xCA, 0xBE, 0xBA, 0xFE, 0xCA, 0xBE, 0xBA, 0xFE, 0xCA, 0xBE, 0xBA, 0xFE, 0xCA, 0xBE, 0xBA, 0xFE }; 119 | #elif __SIZEOF_LONG__ == 8 120 | unsigned long val = 0xDEADBEEFCAFEBABE; 121 | unsigned char setVal[] = { 0xCA, 0xEF, 0xBE, 0xAD, 0xDE, 0xBE, 0xBA, 0xFE, 0xCA, 0xEF, 0xBE, 0xAD, 0xDE, 0xBE, 0xBA, 0xFE }; 122 | #endif 123 | 124 | void *r = fslc_memset_l(testArray+3, val, 16); 125 | memcpy(expected+3, setVal, 16); 126 | 127 | CHECK_ARRAY_EQUAL(expected, testArray, TESTARRAY_SIZE); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /tests/bsearch_i_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "stdlibx.h" 3 | 4 | 5 | static void *high_range; 6 | static void *low_range; 7 | static void *key_ptr; 8 | 9 | static int cmp_intp(const void *lhs, const void *rhs) 10 | { 11 | CHECK((lhs >= low_range && lhs < high_range) || lhs == key_ptr); 12 | CHECK((rhs >= low_range && rhs < high_range) || rhs == key_ptr); 13 | 14 | return *((int*)lhs) - *((int*)rhs); 15 | } 16 | 17 | SUITE(BSearchI) 18 | { 19 | TEST(FindItemEven) 20 | { 21 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 22 | 23 | int key = 30; 24 | 25 | low_range = arr; 26 | high_range = arr + 8; 27 | key_ptr = &key; 28 | 29 | int found = fslc_bsearch_i(&key, arr, 8, sizeof(int), cmp_intp); 30 | 31 | CHECK_EQUAL(2, found); 32 | } 33 | 34 | TEST(FindItemOdd) 35 | { 36 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 37 | 38 | int key = 30; 39 | 40 | low_range = arr; 41 | high_range = arr + 9; 42 | key_ptr = &key; 43 | 44 | int found = fslc_bsearch_i(&key, arr, 9, sizeof(int), cmp_intp); 45 | 46 | CHECK_EQUAL(2, found); 47 | } 48 | 49 | TEST(FindLargestItemEven) 50 | { 51 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 52 | 53 | int key = 80; 54 | 55 | low_range = arr; 56 | high_range = arr + 8; 57 | key_ptr = &key; 58 | 59 | int found = fslc_bsearch_i(&key, arr, 8, sizeof(int), cmp_intp); 60 | 61 | CHECK_EQUAL(7, found); 62 | } 63 | 64 | TEST(FindLargestItemOdd) 65 | { 66 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 67 | 68 | int key = 90; 69 | 70 | low_range = arr; 71 | high_range = arr + 9; 72 | key_ptr = &key; 73 | 74 | int found = fslc_bsearch_i(&key, arr, 9, sizeof(int), cmp_intp); 75 | 76 | CHECK_EQUAL(8, found); 77 | } 78 | 79 | TEST(FindSmallestItemEven) 80 | { 81 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 82 | 83 | int key = 10; 84 | 85 | low_range = arr; 86 | high_range = arr + 8; 87 | key_ptr = &key; 88 | 89 | int found = fslc_bsearch_i(&key, arr, 8, sizeof(int), cmp_intp); 90 | 91 | CHECK_EQUAL(0, found); 92 | } 93 | 94 | TEST(FindSmallestItemOdd) 95 | { 96 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 97 | 98 | int key = 10; 99 | 100 | low_range = arr; 101 | high_range = arr + 9; 102 | key_ptr = &key; 103 | 104 | int found = fslc_bsearch_i(&key, arr, 9, sizeof(int), cmp_intp); 105 | 106 | CHECK_EQUAL(0, found); 107 | } 108 | 109 | TEST(NotFindSmallestItemEven) 110 | { 111 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 112 | 113 | int key = 0; 114 | 115 | low_range = arr; 116 | high_range = arr + 8; 117 | key_ptr = &key; 118 | 119 | int found = fslc_bsearch_i(&key, arr, 8, sizeof(int), cmp_intp); 120 | 121 | CHECK_EQUAL(~0, found); 122 | } 123 | 124 | TEST(NotFindSmallestItemOdd) 125 | { 126 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 127 | 128 | int key = 0; 129 | 130 | low_range = arr; 131 | high_range = arr + 9; 132 | key_ptr = &key; 133 | 134 | int found = fslc_bsearch_i(&key, arr, 9, sizeof(int), cmp_intp); 135 | 136 | CHECK_EQUAL(~0, found); 137 | } 138 | 139 | TEST(NotFindItemEven) 140 | { 141 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 142 | 143 | int key = 65; 144 | 145 | low_range = arr; 146 | high_range = arr + 8; 147 | key_ptr = &key; 148 | 149 | int found = fslc_bsearch_i(&key, arr, 8, sizeof(int), cmp_intp); 150 | 151 | CHECK_EQUAL(~6, found); 152 | } 153 | 154 | TEST(NotFindItemOdd) 155 | { 156 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 157 | 158 | int key = 25; 159 | 160 | low_range = arr; 161 | high_range = arr + 9; 162 | key_ptr = &key; 163 | 164 | int found = fslc_bsearch_i(&key, arr, 9, sizeof(int), cmp_intp); 165 | 166 | CHECK_EQUAL(~2, found); 167 | } 168 | 169 | TEST(NotFindLargestItemEven) 170 | { 171 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 172 | 173 | int key = 90; 174 | 175 | low_range = arr; 176 | high_range = arr + 8; 177 | key_ptr = &key; 178 | 179 | int found = fslc_bsearch_i(&key, arr, 8, sizeof(int), cmp_intp); 180 | 181 | CHECK_EQUAL(~8, found); 182 | } 183 | 184 | TEST(NotFindLargestItemOdd) 185 | { 186 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 187 | 188 | int key = 95; 189 | 190 | low_range = arr; 191 | high_range = arr + 9; 192 | key_ptr = &key; 193 | 194 | int found = fslc_bsearch_i(&key, arr, 9, sizeof(int), cmp_intp); 195 | 196 | CHECK_EQUAL(~9, found); 197 | } 198 | } -------------------------------------------------------------------------------- /tests/bsearch_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fslc_stdlib.h" 3 | 4 | 5 | static void *high_range; 6 | static void *low_range; 7 | static void *key_ptr; 8 | 9 | static int cmp_intp(const void *lhs, const void *rhs) 10 | { 11 | CHECK((lhs >= low_range && lhs < high_range) || lhs == key_ptr); 12 | CHECK((rhs >= low_range && rhs < high_range) || rhs == key_ptr); 13 | 14 | return *((int*)lhs) - *((int*)rhs); 15 | } 16 | 17 | SUITE(BSearch) 18 | { 19 | TEST(FindItemEven) 20 | { 21 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 22 | 23 | int key = 30; 24 | 25 | low_range = arr; 26 | high_range = arr + 8; 27 | key_ptr = &key; 28 | 29 | int *found = (int *)fslc_bsearch(&key, arr, 8, sizeof(int), cmp_intp); 30 | 31 | CHECK_EQUAL(arr + 2, found); 32 | } 33 | 34 | TEST(FindItemOdd) 35 | { 36 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 37 | 38 | int key = 30; 39 | 40 | low_range = arr; 41 | high_range = arr + 9; 42 | key_ptr = &key; 43 | 44 | int *found = (int *)fslc_bsearch(&key, arr, 9, sizeof(int), cmp_intp); 45 | 46 | CHECK_EQUAL(arr + 2, found); 47 | } 48 | 49 | TEST(FindLargestItemEven) 50 | { 51 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 52 | 53 | int key = 80; 54 | 55 | low_range = arr; 56 | high_range = arr + 8; 57 | key_ptr = &key; 58 | 59 | int *found = (int *)fslc_bsearch(&key, arr, 8, sizeof(int), cmp_intp); 60 | 61 | CHECK_EQUAL(arr + 7, found); 62 | } 63 | 64 | TEST(FindLargestItemOdd) 65 | { 66 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 67 | 68 | int key = 90; 69 | 70 | low_range = arr; 71 | high_range = arr + 9; 72 | key_ptr = &key; 73 | 74 | int *found = (int *)fslc_bsearch(&key, arr, 9, sizeof(int), cmp_intp); 75 | 76 | CHECK_EQUAL(arr + 8, found); 77 | } 78 | 79 | TEST(FindSmallestItemEven) 80 | { 81 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 82 | 83 | int key = 10; 84 | 85 | low_range = arr; 86 | high_range = arr + 8; 87 | key_ptr = &key; 88 | 89 | int *found = (int *)fslc_bsearch(&key, arr, 8, sizeof(int), cmp_intp); 90 | 91 | CHECK_EQUAL(arr, found); 92 | } 93 | 94 | TEST(FindSmallestItemOdd) 95 | { 96 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 97 | 98 | int key = 10; 99 | 100 | low_range = arr; 101 | high_range = arr + 9; 102 | key_ptr = &key; 103 | 104 | int *found = (int *)fslc_bsearch(&key, arr, 9, sizeof(int), cmp_intp); 105 | 106 | CHECK_EQUAL(arr, found); 107 | } 108 | 109 | TEST(NotFindLargestItemEven) 110 | { 111 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 112 | 113 | int key = 90; 114 | 115 | low_range = arr; 116 | high_range = arr + 8; 117 | key_ptr = &key; 118 | 119 | int *found = (int *)fslc_bsearch(&key, arr, 8, sizeof(int), cmp_intp); 120 | 121 | CHECK(found == nullptr); 122 | } 123 | 124 | TEST(NotFindLargestItemOdd) 125 | { 126 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 127 | 128 | int key = 100; 129 | 130 | low_range = arr; 131 | high_range = arr + 9; 132 | key_ptr = &key; 133 | 134 | int *found = (int *)fslc_bsearch(&key, arr, 9, sizeof(int), cmp_intp); 135 | 136 | CHECK(found == nullptr); 137 | } 138 | 139 | TEST(NotFindSmallestItemEven) 140 | { 141 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 142 | 143 | int key = 0; 144 | 145 | low_range = arr; 146 | high_range = arr + 8; 147 | key_ptr = &key; 148 | 149 | int *found = (int *)fslc_bsearch(&key, arr, 8, sizeof(int), cmp_intp); 150 | 151 | CHECK(found == nullptr); 152 | } 153 | 154 | TEST(NotFindSmallestItemOdd) 155 | { 156 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 157 | 158 | int key = 0; 159 | 160 | low_range = arr; 161 | high_range = arr + 9; 162 | key_ptr = &key; 163 | 164 | int *found = (int *)fslc_bsearch(&key, arr, 9, sizeof(int), cmp_intp); 165 | 166 | CHECK(found == nullptr); 167 | } 168 | 169 | TEST(NotFindItemEven) 170 | { 171 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 172 | 173 | int key = 65; 174 | 175 | low_range = arr; 176 | high_range = arr + 8; 177 | key_ptr = &key; 178 | 179 | int *found = (int *)fslc_bsearch(&key, arr, 8, sizeof(int), cmp_intp); 180 | 181 | CHECK(found == nullptr); 182 | } 183 | 184 | TEST(NotFindItemOdd) 185 | { 186 | int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; 187 | 188 | int key = 25; 189 | 190 | low_range = arr; 191 | high_range = arr + 9; 192 | key_ptr = &key; 193 | 194 | int *found = (int *)fslc_bsearch(&key, arr, 9, sizeof(int), cmp_intp); 195 | 196 | CHECK(found == nullptr); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /tests/Tests.project: -------------------------------------------------------------------------------- 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 | 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 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | None 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | None 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /libc/Libc.project: -------------------------------------------------------------------------------- 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 | 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 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /tests/puts_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stdio_fixture.h" 4 | 5 | SUITE(PutS) 6 | { 7 | TEST_FIXTURE(StdIOFixture, BasicFPutSTest) 8 | { 9 | int r = fslc_fputs("ABCD", &stream); 10 | 11 | FuncCallItem expected[] = { { CalledFunc::PutC, 'A' }, 12 | { CalledFunc::PutC, 'B' }, 13 | { CalledFunc::PutC, 'C' }, 14 | { CalledFunc::PutC, 'D' } }; 15 | 16 | CHECK(r >= 0); 17 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 18 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 19 | CHECK_EQUAL("ABCD", ostring.str()); 20 | } 21 | 22 | TEST_FIXTURE(StdIOFixture, BasicPutSTest) 23 | { 24 | fslc_stdout = &stream; 25 | 26 | int r = fslc_puts("ABCD"); 27 | 28 | FuncCallItem expected[] = { { CalledFunc::PutC, 'A' }, 29 | { CalledFunc::PutC, 'B' }, 30 | { CalledFunc::PutC, 'C' }, 31 | { CalledFunc::PutC, 'D' }, 32 | { CalledFunc::PutC, '\n'} }; 33 | 34 | CHECK(r >= 0); 35 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 36 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 37 | CHECK_EQUAL("ABCD\n", ostring.str()); 38 | } 39 | 40 | TEST_FIXTURE(StdIOFixture, PrePostOpFPutSTest) 41 | { 42 | stream.pre_output = fixture_preop; 43 | stream.post_output = fixture_postop; 44 | 45 | int r = fslc_fputs("ABCD", &stream); 46 | 47 | FuncCallItem expected[] = { { CalledFunc::PreOp, 0 }, 48 | { CalledFunc::PutC, 'A' }, 49 | { CalledFunc::PutC, 'B' }, 50 | { CalledFunc::PutC, 'C' }, 51 | { CalledFunc::PutC, 'D' }, 52 | { CalledFunc::PostOp, 0 } }; 53 | 54 | CHECK(r >= 0); 55 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 56 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 57 | CHECK_EQUAL("ABCD", ostring.str()); 58 | } 59 | 60 | TEST_FIXTURE(StdIOFixture, PrePostOpPutSTest) 61 | { 62 | fslc_stdout = &stream; 63 | stream.pre_output = fixture_preop; 64 | stream.post_output = fixture_postop; 65 | 66 | int r = fslc_puts("ABCD"); 67 | 68 | FuncCallItem expected[] = { { CalledFunc::PreOp, 0 }, 69 | { CalledFunc::PutC, 'A' }, 70 | { CalledFunc::PutC, 'B' }, 71 | { CalledFunc::PutC, 'C' }, 72 | { CalledFunc::PutC, 'D' }, 73 | { CalledFunc::PutC, '\n'}, 74 | { CalledFunc::PostOp, 0 } }; 75 | 76 | CHECK(r >= 0); 77 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 78 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 79 | CHECK_EQUAL("ABCD\n", ostring.str()); 80 | } 81 | 82 | TEST_FIXTURE(StdIOFixture, Eof2FPutSTest) 83 | { 84 | eof_counter = 2; 85 | int r = fslc_fputs("ABCD", &stream); 86 | 87 | FuncCallItem expected[] = { { CalledFunc::PutC, 'A' }, // OK 88 | { CalledFunc::PutC, 'B' }, // OK 89 | { CalledFunc::PutC, 'C' } }; // EOF - stops output 90 | 91 | CHECK(r < 0); 92 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 93 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 94 | CHECK_EQUAL("AB", ostring.str()); 95 | } 96 | 97 | TEST_FIXTURE(StdIOFixture, EofPrePostOpFPutSTest) 98 | { 99 | eof_counter = 2; 100 | stream.pre_output = fixture_preop; 101 | stream.post_output = fixture_postop; 102 | 103 | int r = fslc_fputs("ABCD", &stream); 104 | 105 | FuncCallItem expected[] = { { CalledFunc::PreOp, 0 }, 106 | { CalledFunc::PutC, 'A' }, // OK 107 | { CalledFunc::PutC, 'B' }, // OK 108 | { CalledFunc::PutC, 'C' }, // EOF 109 | { CalledFunc::PostOp, 0 } }; // should call anyway 110 | 111 | CHECK(r < 0); 112 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 113 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 114 | CHECK_EQUAL("AB", ostring.str()); 115 | } 116 | 117 | TEST_FIXTURE(StdIOFixture, EofPrePostOpPutSEarlyTest) 118 | { 119 | eof_counter = 2; 120 | fslc_stdout = &stream; 121 | stream.pre_output = fixture_preop; 122 | stream.post_output = fixture_postop; 123 | 124 | int r = fslc_puts("ABCD"); 125 | 126 | FuncCallItem expected[] = { { CalledFunc::PreOp, 0 }, 127 | { CalledFunc::PutC, 'A' }, // OK 128 | { CalledFunc::PutC, 'B' }, // OK 129 | { CalledFunc::PutC, 'C' }, // EOF 130 | { CalledFunc::PostOp, 0 } };// should call anyway 131 | 132 | CHECK(r < 0); 133 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 134 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 135 | CHECK_EQUAL("AB", ostring.str()); 136 | } 137 | 138 | TEST_FIXTURE(StdIOFixture, EofPrePostOpPutSLastTest) 139 | { 140 | eof_counter = 4; 141 | fslc_stdout = &stream; 142 | stream.pre_output = fixture_preop; 143 | stream.post_output = fixture_postop; 144 | 145 | int r = fslc_puts("ABCD"); 146 | 147 | FuncCallItem expected[] = { { CalledFunc::PreOp, 0 }, 148 | { CalledFunc::PutC, 'A' }, // OK 149 | { CalledFunc::PutC, 'B' }, // OK 150 | { CalledFunc::PutC, 'C' }, // OK 151 | { CalledFunc::PutC, 'D' }, // OK 152 | { CalledFunc::PutC, '\n'}, // EOF - called but returns EOF 153 | { CalledFunc::PostOp, 0 } };// should call anyway 154 | 155 | CHECK(r < 0); 156 | CHECK_EQUAL(sizeof(expected)/sizeof(FuncCallItem), FuncCallLog.size()); 157 | CHECK_ARRAY_EQUAL(expected, FuncCallLog, FuncCallLog.size()); 158 | CHECK_EQUAL("ABCD", ostring.str()); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Freestanding Libc 2 | ================= 3 | 4 | Bare-metal programming poses its own challenges. There's no underlying operating system 5 | providing fancy services. No input/output facilities, no even basic helper functions. Only 6 | the code we provide ourselves. 7 | 8 | ANSI C Standard calls it *freestanding environment*. [GCC requires][gccstd] the freestanding 9 | environment provide some basic functions: `memcpy()`, `memmove()`, `memset()` and `memcmp()`. 10 | It will assume that these functions are present and use them where it feels like. 11 | 12 | [gccstd]: https://gcc.gnu.org/onlinedocs/gcc/Standards.html "Language Standards Supported by GCC" 13 | 14 | Of course, somebody has to provide these functions, and that is the main reason why *FsLibc* 15 | exists. 16 | 17 | Features 18 | ======== 19 | 20 | Memory manipulation 21 | ------------------- 22 | 23 | The bare minimum of *required* memory manipulation functions are: 24 | 25 | * `memset()` - fill memory with specified byte value; 26 | * `memcpy()` - copy memory from one region to another; 27 | * `memmove()` - copy memory from one region to another, safe for overlapping regions; 28 | * `memcmp()` - compare two memory regions. 29 | 30 | As expected, functions are available using include file *string.h*. 31 | 32 | Input/Output 33 | ------------ 34 | 35 | Common debugging technique is to print out tracing messages about program's state at various 36 | points, sometimes called *printf debugging*. Obviously, there is no predefined `printf()` available 37 | and we need to provide our own. But it may be very tricky to get output to work, while there 38 | is no output. *FsLibc* provides pre-built I/O facilities, which requires very little to get them 39 | to work. Provided are: 40 | 41 | * `putchar()` - put single character on `stdout` stream; 42 | * `fputc()` - put single character on specified stream; 43 | * `puts()` - put a sequence of characters on `stdout` stream; 44 | * `fputs()` - put a sequence of characters on specified stream; 45 | * `printf()` - put formatted output on `stdout` stream, varying number of parameters; 46 | * `fprintf()` - put formatted output on specified stream, varying number of parameters; 47 | * `vprintf()` - put formatted output on `stdout` stream, `va_list` parameter; 48 | * `vfprintf()` - put formatted output on specified stream, `va_list` parameter; 49 | * `fwrite()` - output binary block with specified length; 50 | * `getchar()` - read single character from `stdin` stream; 51 | * `getc()` - read single character from specified stream; 52 | * `fgets()` - read a line of text from specified stream into buffer; 53 | * `ungetc()` - "put back" a single character into input stream; 54 | * `fread()` - read binary block from specified stream into buffer. 55 | 56 | There are 2 global variables `stdout` and `stdin` of type `FILE *` provided for usual standard 57 | streams. These, however needs to be set up before use. An example is worth a thousand words: 58 | 59 | ```C 60 | #include 61 | 62 | static int screen_putc(int c, FILE *stream) 63 | { 64 | // put character on the screen 65 | } 66 | 67 | static int keyboard_getc(FILE *stream) 68 | { 69 | // read and return a character from keyboard 70 | } 71 | 72 | static void screen_pre_output(FILE *stream) 73 | { 74 | // read cursor position before output 75 | } 76 | 77 | static void screen_post_output(FILE *stream) 78 | { 79 | // set cursor position after output 80 | } 81 | 82 | FILE scr_term; 83 | 84 | void setup_terminal_io() 85 | { 86 | // required if output is used 87 | scr_term.putc = screen_putc; 88 | 89 | // required if input is used 90 | scr_term.getc = keyboard_getc; 91 | 92 | // optional 93 | scr_term.pre_output = screen_pre_output; 94 | scr_term.post_output = screen_post_output; 95 | 96 | // required initial state if input 97 | // is used 98 | scr_term.ungetc_buf = -1; 99 | 100 | // pointer to custom data 101 | scr_term.user_ptr = NULL; 102 | 103 | // initialize needed streams 104 | stdin = stdout = &scr_term; 105 | } 106 | ``` 107 | 108 | User is required to provide functions that do the actual I/O and 109 | specify them while initializing `FILE` structure. Obviously, if 110 | user does not intend to use input and need no any additional actions 111 | before/after output, the bare minimum is to provide a single function 112 | which puts a single character on the screen, sends it over UART or 113 | signals it some other way (blink a LED in Morse code, if you like). 114 | 115 | Input/output functions are available from header file *stdio.h*. 116 | 117 | String manipulation 118 | ------------------- 119 | 120 | Another frequently used class of functions in C standard library is functions for 121 | string manipulation. *FsLibc* provides a number of (by author's opinion) most used 122 | ones: 123 | 124 | * `strlen()` - get string length; 125 | * `strcpy()` - copy string; 126 | * `strncpy()` - copy string, limit length; 127 | * `strcmp()` - compare two strings; 128 | * `strncmp()` - compare two strings, limit length; 129 | * `strchr()` - locate first occurrence of character in string; 130 | * `strstr()` - locate substring; 131 | * `strtok_r()` - split string into tokens; 132 | * `strpbrk()` - locate specified characters in string; 133 | * `strspn()` - count specified characters at the beginning of string. 134 | 135 | Since there are no external dependencies, no additional setup is required. Functions 136 | are available from header file *string.h*. 137 | 138 | Miscellaneous utilities 139 | ----------------------- 140 | 141 | C standard library also contains handy routines that are hard to attribute to 142 | particular group. *FsLibc* provides: 143 | 144 | * `bsearch()` - binary search in array; 145 | * `assert()` - validate preconditions in code. 146 | 147 | External dependencies 148 | ===================== 149 | 150 | In order to use several facilities of *FsLibc*, few external dependencies has to be provided 151 | by other means: 152 | 153 | * `__fslc_assert_fail()` - function to be called when assertion fails. See *fslc/fslc_assert.h* for exact prototype. 154 | 155 | 156 | Compatibility 157 | ============= 158 | 159 | *FsLibc* is intended to be a subset of "normal" C Standard Library. The majority of functions 160 | should behave just like their counterparts from standard library (file a bug, if they do not). 161 | 162 | Small exception is *printf* family of functions - they implement only subset of format string 163 | functionality. Only `%s`, `%c`, `%d`, `%i`, `%u`, `%x`, `%X`, `%p` specifiers are supported, no 164 | floating-point support whatsoever. No additional formatting options, with exception of argument 165 | length (`l` and `ll`) are supported. In other words - what works with *FsLibc* will work elsewhere, 166 | but not other way around. 167 | 168 | Another deviance (at least for current version) is that input functions do not distinguish 169 | between EOF and error conditions. But in freestanding environment there is no concept of file, 170 | consequently end-of-file condition makes no much sense anyway. So, if input fails, it must be 171 | error of some sort. 172 | 173 | Library extensions 174 | ------------------ 175 | 176 | While main purpose of *FsLibc* is to provide *compatible* functions, there are some which, while 177 | not compatible, are just too useful to be left out. Especially if they come as a byproduct of 178 | implementing the compatible ones. 179 | 180 | * `memset_l()` - fill the memory using byte pattern from *long* argument. Very useful for filling 181 | memory with *0xDEADBEEF*-style patterns. Internally used by `memset()`. 182 | * `memset_32()` - fill the memory using byte pattern from 32-bit argument. While `memset_l()` is 183 | fine on 32-bit systems, on 64-bit systems it is too tiresome to specify long 64-bit arguments. 184 | * `strcpy_e()` - copy string, just as `strcpy()`, but return a pointer to the *end of dest* - 185 | pointing to terminating *\0* character. This way it is way more useful for string concatenation. 186 | More so - it's the natural value for *dest* after copying and additional steps are required to 187 | preserve original one. 188 | * `strncpy_e()` - behaves just like `strncpy()`, but also returns pointer to the end of the string. 189 | Returned value points to address just after the last non-\0 character copied. 190 | * `bsearch_i()` - behaves like `bsearch()`, but returns the index of the found item in the array. If 191 | key is not found, a negative number, bitwise complement of the index of the first item that is 192 | larger than key (or bitwise complement of num, if key is larger than all items in the array). 193 | 194 | It is recommended to use standards compliant versions where possible, turning to extension ones only 195 | when it is absolutely necessary (like - when you are about to implement it yourself anyway). Extension 196 | functions are available from include files *fslc/stringx.h* and *fslc/stdlibx.h*. 197 | 198 | Build and install 199 | ================= 200 | 201 | *FsLibc* uses [CMake][cmake] build system to compile its sources. There are 3 build profiles defined: 202 | 203 | * **Debug** - use while developing. Enables debugging information, code coverage information; 204 | * **Release** - compiles without debug information, full code optimizations. Function names in 205 | compiled library are what is expected in *C Standard Library*. Use this mode to prepare library 206 | for linking into kernel; 207 | * **RelCheck** - compiles with *almost release* settings. No debug info, full code optimization. The 208 | only difference from *Release* is that function names are still prefixed with `fslc_`. The purpose 209 | of this mode is to run unit tests on release code. Obviously, you still can not be absolutely sure if 210 | it will behave on different platform. But you may try to test on target platform running Linux. 211 | 212 | For *Debug* and *RelCheck* the compile commands are almost identical: 213 | 214 | cmake -DCMAKE_BUILD_TYPE=Debug . 215 | make 216 | make test 217 | 218 | **Warning**: do not attempt to run *make install* here, especially with elevated privileges. You risk 219 | to overwrite your host system's header files. 220 | 221 | For *Release* configuration, most likely, you will want to cross-compile the library for your 222 | target platform. Edit file *cross-toolchain.cmake*, specify the compiler toolchain: 223 | 224 | # specify the cross compiler 225 | CMAKE_FORCE_C_COMPILER(/usr/local/cross/bin/arm-elf-eabi-gcc GNU) 226 | CMAKE_FORCE_CXX_COMPILER(/usr/local/cross/bin/arm-elf-eabi-g++ GNU) 227 | 228 | This will switch compilers to *arm-elf-eabi* platform, installed at */usr/local/cross*. Now 229 | configure the system: 230 | 231 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=cross-toolchain.cmake \ 232 | -DCMAKE_INSTALL_PREFIX=/home/devel/fslibc . 233 | make -C libc 234 | make -C libc install 235 | 236 | This will compile the library and then install it at location */home/devel/fslibc* (you may want 237 | to adjust it for your needs). Note that we are not even trying to build tests here. Most likely they 238 | will not compile, and even if they did they would not run, as host and target platforms differ. 239 | 240 | Note: that if you receive an error about missing stdint.h while using a freestanding compiler, you 241 | may need to append `-ffreestanding` to the CFLAGS list. 242 | 243 | [cmake]: https://cmake.org/ "CMake" 244 | 245 | Development and tests 246 | ===================== 247 | 248 | As C library is one of most fundamental piece of software, it's a very good idea to make it as bug-free 249 | as possible. *FsLibc* uses white-box unit tests with help of [UnitTest++][unittestpp] framework to ensure 250 | correct behavior. The policy is to get 100% line and branch coverage at all times. If a bug is discovered, 251 | it must be first reproduced with appropriate unit test and only then fixed. 252 | 253 | [CodeLite][codelite] is used for development. Its *workspace* and *project* files are also included in 254 | source files and coexist with [CMake][cmake] easily. 255 | 256 | [unittestpp]: https://unittest-cpp.github.io/ "UnitTest++ framework" 257 | [codelite]: http://codelite.org/ "CodeLite IDE" 258 | -------------------------------------------------------------------------------- /libc/src/fslc_vfprintf.c: -------------------------------------------------------------------------------- 1 | #include "fslc_stdio.h" 2 | 3 | /* There'a a funny behaviour of va_list and va_arg() macros: 4 | * - on x86_64 compiler generates a branch of some sort for each va_arg() macro. Normally it is not a problem, 5 | * however it kinda screws up branch coverage analysis. Therefore I decided to move va_arg() accesses into 6 | * dedicated functions, minimizing the issue to one untaken branch per access function. 7 | * - passing va_list by value works fine on x86_64, but makes some tests to fail on i386. It seems that modifications 8 | * done by va_arg() is not passed back to caller. Subsequent calls to va_arg() or access functions returns wrong 9 | * values on that platform. 10 | * - OK, then. Let's pass pointer to va_list instead. Not so fast. Works fine on i386, but fails to compile on 11 | * x86_64. Fine! Wrapping va_list into a dedicated struct and passing around pointer to it. 12 | * 13 | * Why such a fuss about a few untaken branches in tests? Well, just because! Also, if I ever decide to refactor 14 | * _fslc_vfprintf_impl() - the case statement is getting a bit long and messy, it should make things easier if 15 | * argument list can be passed around freely (as opposed to using it from single function). 16 | */ 17 | 18 | struct va_list_w 19 | { 20 | va_list arg; 21 | }; 22 | 23 | /* Prototype for printf's internal implementation */ 24 | static int _fslc_vfprintf_impl(FSLC_FILE *stream, const char *format, struct va_list_w *args); 25 | 26 | 27 | /* Main exported function */ 28 | int fslc_vfprintf(FSLC_FILE *stream, const char *format, va_list arg) 29 | { 30 | if (stream->pre_output) stream->pre_output(stream); 31 | 32 | struct va_list_w argw; 33 | va_copy(argw.arg, arg); // can not assign directly, should make a copy 34 | 35 | int res = _fslc_vfprintf_impl(stream, format, &argw); 36 | 37 | va_end(argw.arg); // and free it after use 38 | 39 | if (stream->post_output) stream->post_output(stream); 40 | 41 | return res; 42 | } 43 | 44 | /* Prototype to private FSLIBC function - implemented elsewhere */ 45 | int _fslc_fputs_impl(const char *str, FSLC_FILE *stream); 46 | 47 | 48 | /* Prototypes for internal functions */ 49 | static int _fslc_put_sint_l(signed long v, FSLC_FILE *stream); 50 | static int _fslc_put_uint_l(unsigned long v, FSLC_FILE *stream); 51 | static int _fslc_put_hex_l(unsigned long v, FSLC_FILE *stream, char alpha); 52 | 53 | static int _get_sint_arg(struct va_list_w *arg); 54 | static unsigned _get_uint_arg(struct va_list_w *arg); 55 | static long long _get_slonglong_arg(struct va_list_w *arg); 56 | static unsigned long long _get_ulonglong_arg(struct va_list_w *arg); 57 | static void *_get_ptr_arg(struct va_list_w *arg); 58 | 59 | /* There are some considerations when formatting Integers for output: 60 | * - on 32-bit systems integers will mostly be 32 bits long, except when one REALLY 61 | * wants to print long long. It should be more optimal to use 32-bit calculations 62 | * when possible and invoke 64-bit only when needed. To support that we provide 2 63 | * separate implementations. 64 | * - on 64-bit systems may be 32 or 64 bits, but there is no real benefit from 65 | * using shorter bit size. Hence common implementation. 66 | * - this library does not aim to support systems with shorter integer sizes (like 16-bit) 67 | * but it it did, it would probably make sense to provide optimized ports for these cases 68 | * as well. 69 | * 70 | * Buffer size calculations: 71 | * Max UInt32 fits in 10 bytes (+1 for zero terminator) decimal 72 | * 2**32 - 1 == 4294967295z 73 | * FFFFFFFFz 74 | * 01234567890 75 | * 76 | * Max UInt64 fits in 10 bytes (and +1 for \0) 77 | * 2**64 -1 == 18446744073709551615z 78 | * FFFFFFFFFFFFFFFFz 79 | * 012345678901234567890 80 | */ 81 | 82 | #define BUFSIZE_LONG_LONG_DECIMAL 20 83 | #define BUFSIZE_LONG_HEX (__SIZEOF_LONG__ * 2) 84 | #define BUFSIZE_LONG_LONG_HEX (__SIZEOF_LONG_LONG__ * 2) 85 | #if __SIZEOF_LONG__ == 4 86 | 87 | #define BUFSIZE_LONG_DECIMAL 10 88 | static int _fslc_put_sint_ll(signed long long v, FSLC_FILE *stream); 89 | static int _fslc_put_uint_ll(unsigned long long v, FSLC_FILE *stream); 90 | static int _fslc_put_hex_ll(unsigned long long v, FSLC_FILE *stream, char alpha); 91 | 92 | #define _get_slong_arg _get_sint_arg 93 | #define _get_ulong_arg _get_uint_arg 94 | 95 | #elif __SIZEOF_LONG__ == 8 96 | 97 | #define BUFSIZE_LONG_DECIMAL BUFSIZE_LONG_LONG_DECIMAL 98 | #define _fslc_put_sint_ll _fslc_put_sint_l 99 | #define _fslc_put_uint_ll _fslc_put_uint_l 100 | #define _fslc_put_hex_ll _fslc_put_hex_l 101 | 102 | #define _get_slong_arg _get_slonglong_arg 103 | #define _get_ulong_arg _get_ulonglong_arg 104 | 105 | #endif 106 | 107 | #define FLAG_LONG 1 108 | #define FLAG_VERYLONG 3 109 | 110 | static int _fslc_vfprintf_impl(FSLC_FILE *stream, const char *format, struct va_list_w *arg) 111 | { 112 | int res = 0; 113 | int pr; 114 | const char *c; 115 | 116 | for (c = format; *c; ++c) 117 | { 118 | if (*c == '%') 119 | { 120 | int flags = 0; 121 | 122 | for (;;) 123 | { 124 | ++c; 125 | switch (*c) 126 | { 127 | case 's': 128 | pr = _fslc_fputs_impl((const char *)_get_ptr_arg(arg), stream); 129 | if (pr < 0) return pr; 130 | res += pr; 131 | break; 132 | 133 | case 'c': 134 | pr = stream->putc(_get_sint_arg(arg), stream); 135 | if (pr < 0) return pr; 136 | ++res; 137 | break; 138 | 139 | case '%': 140 | pr = stream->putc('%', stream); 141 | if (pr < 0) return pr; 142 | ++res; 143 | break; 144 | 145 | case 'i': 146 | case 'd': 147 | if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG) 148 | pr = _fslc_put_sint_ll(_get_slonglong_arg(arg), stream); 149 | else if (flags & FLAG_LONG) 150 | pr = _fslc_put_sint_l(_get_slong_arg(arg), stream); 151 | else 152 | pr = _fslc_put_sint_l(_get_sint_arg(arg), stream); 153 | 154 | if (pr < 0) return pr; 155 | res += pr; 156 | break; 157 | 158 | case 'u': 159 | if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG) 160 | pr = _fslc_put_uint_ll(_get_ulonglong_arg(arg), stream); 161 | else if (flags & FLAG_LONG) 162 | pr = _fslc_put_uint_l(_get_ulong_arg(arg), stream); 163 | else 164 | pr = _fslc_put_uint_l(_get_uint_arg(arg), stream); 165 | 166 | if (pr < 0) return pr; 167 | res += pr; 168 | break; 169 | 170 | case 'x': 171 | if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG) 172 | pr = _fslc_put_hex_ll(_get_ulonglong_arg(arg), stream, 'a'); 173 | else if (flags & FLAG_LONG) 174 | pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'a'); 175 | else 176 | pr = _fslc_put_hex_l(_get_uint_arg(arg), stream, 'a'); 177 | 178 | if (pr < 0) return pr; 179 | res += pr; 180 | break; 181 | 182 | case 'X': 183 | if ((flags & FLAG_VERYLONG) == FLAG_VERYLONG) 184 | pr = _fslc_put_hex_ll(_get_ulonglong_arg(arg), stream, 'A'); 185 | else if (flags & FLAG_LONG) 186 | pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'A'); 187 | else 188 | pr = _fslc_put_hex_l(_get_uint_arg(arg), stream, 'A'); 189 | 190 | if (pr < 0) return pr; 191 | res += pr; 192 | break; 193 | 194 | case 'p': 195 | pr = _fslc_fputs_impl("0x", stream); 196 | if (pr < 0) return pr; 197 | res += pr; 198 | 199 | pr = _fslc_put_hex_l(_get_ulong_arg(arg), stream, 'a'); 200 | 201 | if (pr < 0) return pr; 202 | res += pr; 203 | break; 204 | 205 | case 'l': 206 | if (flags & FLAG_LONG) 207 | flags |= FLAG_VERYLONG; 208 | else 209 | flags |= FLAG_LONG; 210 | continue; 211 | } 212 | break; 213 | } 214 | } else { 215 | pr = stream->putc(*c, stream); 216 | if (pr < 0) return pr; 217 | ++res; 218 | } 219 | } 220 | 221 | return res; 222 | } 223 | 224 | static int _get_sint_arg(struct va_list_w *arg) 225 | { 226 | return va_arg(arg->arg, signed int); 227 | } 228 | 229 | static unsigned _get_uint_arg(struct va_list_w *arg) 230 | { 231 | return va_arg(arg->arg, unsigned int); 232 | } 233 | 234 | static long long _get_slonglong_arg(struct va_list_w *arg) 235 | { 236 | return va_arg(arg->arg, signed long long); 237 | } 238 | 239 | static unsigned long long _get_ulonglong_arg(struct va_list_w *arg) 240 | { 241 | return va_arg(arg->arg, unsigned long long); 242 | } 243 | 244 | static void *_get_ptr_arg(struct va_list_w *arg) 245 | { 246 | return va_arg(arg->arg, void *); 247 | } 248 | 249 | static int _fslc_put_sint_l(signed long v, FSLC_FILE *stream) 250 | { 251 | if (v < 0) 252 | { 253 | int pr = stream->putc('-', stream); 254 | if (pr < 0) return pr; 255 | 256 | pr = _fslc_put_uint_l(-v, stream); 257 | if (pr < 0) return pr; 258 | 259 | return pr+1; 260 | } else 261 | return _fslc_put_uint_l(v, stream); 262 | } 263 | 264 | static int _fslc_put_uint_l(unsigned long v, FSLC_FILE *stream) 265 | { 266 | char dbuff[BUFSIZE_LONG_DECIMAL+1], *p; 267 | 268 | dbuff[BUFSIZE_LONG_DECIMAL] = 0; 269 | 270 | for (p = dbuff + BUFSIZE_LONG_DECIMAL; v ; v /= 10) 271 | { 272 | *(--p) = (v % 10) + '0'; 273 | } 274 | 275 | if (*p == 0) *(--p) = '0'; 276 | 277 | return _fslc_fputs_impl(p, stream); 278 | } 279 | 280 | static int _fslc_put_hex_l(unsigned long v, FSLC_FILE *stream, char alpha) 281 | { 282 | char dbuff[BUFSIZE_LONG_HEX+1], *p; 283 | 284 | dbuff[BUFSIZE_LONG_HEX] = 0; 285 | 286 | for (p = dbuff + BUFSIZE_LONG_HEX; v ; v >>= 4) 287 | { 288 | char digit = (v & 0xF); 289 | *(--p) = digit < 10 ? digit + '0' : digit - 10 + alpha; 290 | } 291 | 292 | if (*p == 0) *(--p) = '0'; 293 | 294 | return _fslc_fputs_impl(p, stream); 295 | } 296 | 297 | #if __SIZEOF_LONG__ == 4 298 | 299 | static int _fslc_put_sint_ll(signed long long v, FSLC_FILE *stream) 300 | { 301 | if (v < 0) 302 | { 303 | int pr = stream->putc('-', stream); 304 | if (pr < 0) return pr; 305 | 306 | pr = _fslc_put_uint_ll(-v, stream); 307 | if (pr < 0) return pr; 308 | 309 | return pr+1; 310 | } else 311 | return _fslc_put_uint_ll(v, stream); 312 | } 313 | 314 | static int _fslc_put_uint_ll(unsigned long long v, FSLC_FILE *stream) 315 | { 316 | char dbuff[BUFSIZE_LONG_LONG_DECIMAL+1], *p; 317 | 318 | dbuff[BUFSIZE_LONG_LONG_DECIMAL] = 0; 319 | 320 | for (p = dbuff + BUFSIZE_LONG_LONG_DECIMAL; v ; v /= 10) 321 | { 322 | *(--p) = (v % 10) + '0'; 323 | } 324 | 325 | if (*p == 0) *(--p) = '0'; 326 | 327 | return _fslc_fputs_impl(p, stream); 328 | } 329 | 330 | static int _fslc_put_hex_ll(unsigned long long v, FSLC_FILE *stream, char alpha) 331 | { 332 | char dbuff[BUFSIZE_LONG_LONG_HEX+1], *p; 333 | 334 | dbuff[BUFSIZE_LONG_LONG_HEX] = 0; 335 | 336 | for (p = dbuff + BUFSIZE_LONG_LONG_HEX; v ; v >>= 4) 337 | { 338 | char digit = (v & 0xF); 339 | *(--p) = digit < 10 ? digit + '0' : digit - 10 + alpha; 340 | } 341 | 342 | if (*p == 0) *(--p) = '0'; 343 | 344 | return _fslc_fputs_impl(p, stream); 345 | } 346 | 347 | #endif 348 | -------------------------------------------------------------------------------- /tests/printf_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stdio_fixture.h" 4 | 5 | SUITE(PrintF) 6 | { 7 | TEST_FIXTURE(StdIOFixture, BasicPrintFTest) 8 | { 9 | int r = fslc_fprintf(&stream, "Hello, World!\n"); 10 | 11 | CHECK_EQUAL("Hello, World!\n", ostring.str()); 12 | CHECK_EQUAL(ostring.str().size(), r); 13 | } 14 | 15 | TEST_FIXTURE(StdIOFixture, PrintFStringTest) 16 | { 17 | int r = fslc_fprintf(&stream, "Hello from %s!\n", "PrintF"); 18 | 19 | CHECK_EQUAL("Hello from PrintF!\n", ostring.str()); 20 | CHECK_EQUAL(ostring.str().size(), r); 21 | } 22 | 23 | TEST_FIXTURE(StdIOFixture, PrintF2StringsTest) 24 | { 25 | int r = fslc_fprintf(&stream, "%s from %s!\n", "Hello", "PrintF"); 26 | 27 | CHECK_EQUAL("Hello from PrintF!\n", ostring.str()); 28 | CHECK_EQUAL(ostring.str().size(), r); 29 | } 30 | 31 | TEST_FIXTURE(StdIOFixture, PrintFCharTest) 32 | { 33 | int r = fslc_fprintf(&stream, "Hello, %corld!\n", 'W'); 34 | 35 | CHECK_EQUAL("Hello, World!\n", ostring.str()); 36 | CHECK_EQUAL(ostring.str().size(), r); 37 | } 38 | 39 | TEST_FIXTURE(StdIOFixture, PrintFPercentTest) 40 | { 41 | int r = fslc_fprintf(&stream, "Special offer: 50%% off!"); 42 | 43 | CHECK_EQUAL("Special offer: 50% off!", ostring.str()); 44 | CHECK_EQUAL(ostring.str().size(), r); 45 | } 46 | 47 | TEST_FIXTURE(StdIOFixture, PrintFPrePostMultiTest) 48 | { 49 | stream.pre_output = fixture_preop; 50 | stream.post_output = fixture_postop; 51 | 52 | int r = fslc_fprintf(&stream, "Testing %s%% of all possibilities%c", "a few ", '!'); 53 | 54 | int e = eprintf("Testing %s%% of all possibilities%c", "a few ", '!'); 55 | 56 | const char *expected_str = expected_fstring.get(); 57 | 58 | std::vector expected_calls; 59 | expected_calls.push_back({ CalledFunc::PreOp, 0 }); 60 | for (const char *c = expected_str; *c; ++c) 61 | expected_calls.push_back({ CalledFunc::PutC, *c }); 62 | expected_calls.push_back({ CalledFunc::PostOp, 0 }); 63 | 64 | CHECK_EQUAL(e, r); 65 | CHECK_EQUAL(expected_calls.size(), FuncCallLog.size()); 66 | CHECK_ARRAY_EQUAL(expected_calls, FuncCallLog, FuncCallLog.size()); 67 | 68 | CHECK_EQUAL(expected_str, ostring.str()); 69 | CHECK_EQUAL(ostring.str().size(), r); 70 | } 71 | 72 | TEST_FIXTURE(StdIOFixture, PrintFPrePostMultiEofTest) 73 | { 74 | stream.pre_output = fixture_preop; 75 | stream.post_output = fixture_postop; 76 | 77 | eof_counter = 20; 78 | 79 | int r = fslc_fprintf(&stream, "Testing %s%% of all possibilities%c", "a few ", '!'); 80 | 81 | const char *expected_str = "Testing a few % of a"; 82 | // 12345678901234567890 83 | 84 | std::vector expected_calls; 85 | expected_calls.push_back({ CalledFunc::PreOp, 0 }); 86 | for (const char *c = expected_str; *c; ++c) 87 | expected_calls.push_back({ CalledFunc::PutC, *c }); 88 | expected_calls.push_back({ CalledFunc::PutC, 'l' }); // EOF 89 | expected_calls.push_back({ CalledFunc::PostOp, 0 }); 90 | 91 | CHECK(r < 0); 92 | CHECK_EQUAL(expected_calls.size(), FuncCallLog.size()); 93 | CHECK_ARRAY_EQUAL(expected_calls, FuncCallLog, FuncCallLog.size()); 94 | 95 | CHECK_EQUAL(expected_str, ostring.str()); 96 | } 97 | 98 | TEST_FIXTURE(StdIOFixture, PrintFBasicIntTest) 99 | { 100 | int r = fslc_fprintf(&stream, "The answer is %d!", 42); 101 | 102 | CHECK(r >= 0); 103 | CHECK_EQUAL("The answer is 42!", ostring.str()); 104 | CHECK_EQUAL(ostring.str().size(), r); 105 | } 106 | 107 | TEST_FIXTURE(StdIOFixture, PrintFZeroIntTest) 108 | { 109 | int r = fslc_fprintf(&stream, "Zero is %d!", 0); 110 | 111 | CHECK(r >= 0); 112 | CHECK_EQUAL("Zero is 0!", ostring.str()); 113 | CHECK_EQUAL(ostring.str().size(), r); 114 | } 115 | 116 | TEST_FIXTURE(StdIOFixture, PrintFNegativeTest) 117 | { 118 | int r = fslc_fprintf(&stream, "Less than zero: %d!", -54); 119 | 120 | CHECK(r >= 0); 121 | CHECK_EQUAL("Less than zero: -54!", ostring.str()); 122 | CHECK_EQUAL(ostring.str().size(), r); 123 | } 124 | 125 | TEST_FIXTURE(StdIOFixture, PrintFUIntMaxTest) 126 | { 127 | int r = fslc_fprintf(&stream, "Max uint is %u\n", -1); 128 | 129 | CHECK(r >= 0); 130 | CHECK_EQUAL("Max uint is 4294967295\n", ostring.str()); 131 | CHECK_EQUAL(ostring.str().size(), r); 132 | } 133 | 134 | TEST_FIXTURE(StdIOFixture, PrintFBasicHexTest) 135 | { 136 | int r = fslc_fprintf(&stream, "The answer is %x!", 0x74df); 137 | 138 | CHECK(r >= 0); 139 | CHECK_EQUAL("The answer is 74df!", ostring.str()); 140 | CHECK_EQUAL(ostring.str().size(), r); 141 | } 142 | 143 | TEST_FIXTURE(StdIOFixture, PrintFBasicUpperHexTest) 144 | { 145 | int r = fslc_fprintf(&stream, "The answer is %X!", 0x74df); 146 | 147 | CHECK(r >= 0); 148 | CHECK_EQUAL("The answer is 74DF!", ostring.str()); 149 | CHECK_EQUAL(ostring.str().size(), r); 150 | } 151 | 152 | TEST_FIXTURE(StdIOFixture, PrintFZeroHexTest) 153 | { 154 | int r = fslc_fprintf(&stream, "Zero is %x!", 0); 155 | 156 | CHECK(r >= 0); 157 | CHECK_EQUAL("Zero is 0!", ostring.str()); 158 | CHECK_EQUAL(ostring.str().size(), r); 159 | } 160 | 161 | TEST_FIXTURE(StdIOFixture, PrintFUHExMaxTest) 162 | { 163 | int r = fslc_fprintf(&stream, "Max hex is %x\n", -1); 164 | 165 | CHECK(r >= 0); 166 | CHECK_EQUAL("Max hex is ffffffff\n", ostring.str()); 167 | CHECK_EQUAL(ostring.str().size(), r); 168 | } 169 | 170 | TEST_FIXTURE(StdIOFixture, PrintFLongIntTest) 171 | { 172 | int r = fslc_fprintf(&stream, "The answer is %ld!", 435434432L); 173 | 174 | int e = eprintf("The answer is %ld!", 435434432L); 175 | 176 | CHECK_EQUAL(e, r); 177 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 178 | CHECK_EQUAL(ostring.str().size(), r); 179 | } 180 | 181 | TEST_FIXTURE(StdIOFixture, PrintFLongNegativeTest) 182 | { 183 | int r = fslc_fprintf(&stream, "Less than zero: %ld!", -57299223L); 184 | 185 | int e = eprintf("Less than zero: %ld!", -57299223L); 186 | 187 | CHECK_EQUAL(e, r); 188 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 189 | CHECK_EQUAL(ostring.str().size(), r); 190 | } 191 | 192 | TEST_FIXTURE(StdIOFixture, PrintFULongMaxTest) 193 | { 194 | int r = fslc_fprintf(&stream, "Max ulong is %lu\n", -1L); 195 | 196 | int e = eprintf("Max ulong is %lu\n", -1L); 197 | 198 | CHECK_EQUAL(e, r); 199 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 200 | CHECK_EQUAL(ostring.str().size(), r); 201 | } 202 | 203 | TEST_FIXTURE(StdIOFixture, PrintFULongHexMaxTest) 204 | { 205 | int r = fslc_fprintf(&stream, "Max long hex is %lx\n", -1L); 206 | 207 | int e = eprintf("Max long hex is %lx\n", -1L); 208 | 209 | CHECK_EQUAL(e, r); 210 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 211 | CHECK_EQUAL(ostring.str().size(), r); 212 | } 213 | 214 | TEST_FIXTURE(StdIOFixture, PrintFULongHexUpperMaxTest) 215 | { 216 | int r = fslc_fprintf(&stream, "Max long hex is %lX\n", -1L); 217 | 218 | int e = eprintf("Max long hex is %lX\n", -1L); 219 | 220 | CHECK_EQUAL(e, r); 221 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 222 | CHECK_EQUAL(ostring.str().size(), r); 223 | } 224 | 225 | TEST_FIXTURE(StdIOFixture, PrintFVeryLongIntTest) 226 | { 227 | int r = fslc_fprintf(&stream, "The answer is %lld!", 435432343442444432LL); 228 | 229 | int e = eprintf("The answer is %lld!", 435432343442444432LL); 230 | 231 | CHECK_EQUAL(e, r); 232 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 233 | CHECK_EQUAL(ostring.str().size(), r); 234 | } 235 | 236 | TEST_FIXTURE(StdIOFixture, PrintFVeryLongNegativeTest) 237 | { 238 | int r = fslc_fprintf(&stream, "Less than zero: %lld!", -5729932434424223L); 239 | 240 | int e = eprintf("Less than zero: %lld!", -5729932434424223L); 241 | 242 | CHECK_EQUAL(e, r); 243 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 244 | CHECK_EQUAL(ostring.str().size(), r); 245 | } 246 | 247 | TEST_FIXTURE(StdIOFixture, PrintFUVeryLongMaxTest) 248 | { 249 | int r = fslc_fprintf(&stream, "Max ulonglong is %llu\n", -1L); 250 | 251 | int e = eprintf("Max ulonglong is %llu\n", -1L); 252 | 253 | CHECK_EQUAL(e, r); 254 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 255 | CHECK_EQUAL(ostring.str().size(), r); 256 | } 257 | 258 | TEST_FIXTURE(StdIOFixture, PrintFVeryLongZeroTest) 259 | { 260 | int r = fslc_fprintf(&stream, "The answer is %lld!", 0LL); 261 | 262 | int e = eprintf("The answer is %lld!", 0LL); 263 | 264 | CHECK_EQUAL(e, r); 265 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 266 | CHECK_EQUAL(ostring.str().size(), r); 267 | } 268 | 269 | TEST_FIXTURE(StdIOFixture, PrintFUVeryLongHexDigitsTest) 270 | { 271 | int r = fslc_fprintf(&stream, "Long long hex %llx\n", 0xDEADBEEFCAFE0000LL); 272 | 273 | int e = eprintf("Long long hex %llx\n", 0xDEADBEEFCAFE0000LL); 274 | 275 | CHECK_EQUAL(e, r); 276 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 277 | CHECK_EQUAL(ostring.str().size(), r); 278 | } 279 | 280 | TEST_FIXTURE(StdIOFixture, PrintFUVeryLongHexZeroTest) 281 | { 282 | int r = fslc_fprintf(&stream, "Long long hex zero %llx\n", 0LL); 283 | 284 | int e = eprintf("Long long hex zero %llx\n", 0LL); 285 | 286 | CHECK_EQUAL(e, r); 287 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 288 | CHECK_EQUAL(ostring.str().size(), r); 289 | } 290 | 291 | TEST_FIXTURE(StdIOFixture, PrintFUVeryLongHexMaxTest) 292 | { 293 | int r = fslc_fprintf(&stream, "Max long long hex is %llx\n", -1L); 294 | 295 | int e = eprintf("Max long long hex is %llx\n", -1L); 296 | 297 | CHECK_EQUAL(e, r); 298 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 299 | CHECK_EQUAL(ostring.str().size(), r); 300 | } 301 | 302 | TEST_FIXTURE(StdIOFixture, PrintFUVeryLongUpperHexMaxTest) 303 | { 304 | int r = fslc_fprintf(&stream, "Max long long hex is %llX\n", -1L); 305 | 306 | int e = eprintf("Max long long hex is %llX\n", -1L); 307 | 308 | CHECK_EQUAL(e, r); 309 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 310 | CHECK_EQUAL(ostring.str().size(), r); 311 | } 312 | 313 | TEST_FIXTURE(StdIOFixture, PrintFIntSignEofTest) 314 | { 315 | eof_counter = 10; 316 | int r = fslc_fprintf(&stream, "Will stop %d", -1223); 317 | 318 | int e = eprintf("Will stop "); 319 | 320 | CHECK(r < 0); 321 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 322 | } 323 | 324 | TEST_FIXTURE(StdIOFixture, PrintFIntMiddleEofTest) 325 | { 326 | eof_counter = 12; 327 | int r = fslc_fprintf(&stream, "Will stop %d", -1223); 328 | 329 | int e = eprintf("Will stop -1"); 330 | 331 | CHECK(r < 0); 332 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 333 | } 334 | 335 | TEST_FIXTURE(StdIOFixture, PrintFVeryLongSignEofTest) 336 | { 337 | eof_counter = 10; 338 | int r = fslc_fprintf(&stream, "Will stop %lld", -1223LL); 339 | 340 | int e = eprintf("Will stop "); 341 | 342 | CHECK(r < 0); 343 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 344 | } 345 | 346 | TEST_FIXTURE(StdIOFixture, PrintFVeryLongMiddleEofTest) 347 | { 348 | eof_counter = 12; 349 | int r = fslc_fprintf(&stream, "Will stop %lld", -1223LL); 350 | 351 | int e = eprintf("Will stop -1"); 352 | 353 | CHECK(r < 0); 354 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 355 | } 356 | 357 | TEST_FIXTURE(StdIOFixture, PrintFStringMiddleEofTest) 358 | { 359 | eof_counter = 12; 360 | int r = fslc_fprintf(&stream, "Will stop %s", "1223"); 361 | 362 | int e = eprintf("Will stop 12"); 363 | 364 | CHECK(r < 0); 365 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 366 | } 367 | 368 | TEST_FIXTURE(StdIOFixture, PrintFCharEofTest) 369 | { 370 | eof_counter = 10; 371 | int r = fslc_fprintf(&stream, "Will stop %c", 'a'); 372 | 373 | int e = eprintf("Will stop "); 374 | 375 | CHECK(r < 0); 376 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 377 | } 378 | 379 | TEST_FIXTURE(StdIOFixture, PrintFPercentEofTest) 380 | { 381 | eof_counter = 10; 382 | int r = fslc_fprintf(&stream, "Will stop %%"); 383 | 384 | int e = eprintf("Will stop "); 385 | 386 | CHECK(r < 0); 387 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 388 | } 389 | 390 | TEST_FIXTURE(StdIOFixture, PrintFUIntMiddleEofTest) 391 | { 392 | eof_counter = 12; 393 | int r = fslc_fprintf(&stream, "Will stop %u", 1223); 394 | 395 | int e = eprintf("Will stop 12"); 396 | 397 | CHECK(r < 0); 398 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 399 | } 400 | 401 | TEST_FIXTURE(StdIOFixture, PrintFUHexMiddleEofTest) 402 | { 403 | eof_counter = 12; 404 | int r = fslc_fprintf(&stream, "Will stop %x", 0xA223); 405 | 406 | int e = eprintf("Will stop a2"); 407 | 408 | CHECK(r < 0); 409 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 410 | } 411 | 412 | TEST_FIXTURE(StdIOFixture, PrintFUHEXMiddleEofTest) 413 | { 414 | eof_counter = 12; 415 | int r = fslc_fprintf(&stream, "Will stop %X", 0xA223); 416 | 417 | int e = eprintf("Will stop A2"); 418 | 419 | CHECK(r < 0); 420 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 421 | } 422 | 423 | TEST_FIXTURE(StdIOFixture, PrintPPointerTest) 424 | { 425 | void *ptr = (void *)0x032D47F2; 426 | 427 | int r = fslc_fprintf(&stream, "A pointer: %p!", ptr); 428 | 429 | int e = eprintf("A pointer: %p!", ptr); 430 | 431 | CHECK_EQUAL(e, r); 432 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 433 | CHECK_EQUAL(ostring.str().size(), r); 434 | } 435 | 436 | TEST_FIXTURE(StdIOFixture, PrintPPointerEofPrefixTest) 437 | { 438 | void *ptr = (void *)0x032D47F2; 439 | 440 | int e = eprintf("A pointer: 0"); 441 | 442 | eof_counter = e; 443 | 444 | int r = fslc_fprintf(&stream, "A pointer: %p!", ptr); 445 | 446 | CHECK(r < 0); 447 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 448 | } 449 | 450 | TEST_FIXTURE(StdIOFixture, PrintPPointerEofMiddleTest) 451 | { 452 | void *ptr = (void *)0x032D47F2; 453 | 454 | int e = eprintf("A pointer: 0x32"); 455 | 456 | eof_counter = e; 457 | 458 | int r = fslc_fprintf(&stream, "A pointer: %p!", ptr); 459 | 460 | CHECK(r < 0); 461 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 462 | } 463 | 464 | TEST_FIXTURE(StdIOFixture, PrintFInvalidTest) 465 | { 466 | // How to handle invalid printf format strings is undefined. 467 | // But we should check anyway - just in case. 468 | int r = fslc_fprintf(&stream, "An invalid %k specifier"); 469 | 470 | CHECK(r >= 0); 471 | CHECK_EQUAL("An invalid specifier", ostring.str()); 472 | CHECK_EQUAL(ostring.str().size(), r); 473 | } 474 | 475 | TEST_FIXTURE(StdIOFixture, PrintFStdoutNDefaultTest) 476 | { 477 | FSLC_FILE null_stream; 478 | null_stream.pre_output = null_prepostop; 479 | null_stream.putc = null_putc; 480 | null_stream.post_output = null_prepostop; 481 | 482 | fslc_stdout = &null_stream; 483 | 484 | stream.pre_output = fixture_preop; 485 | stream.post_output = fixture_postop; 486 | 487 | int r = fslc_fprintf(&stream, "Hello, World!\n"); 488 | int e = eprintf("Hello, World!\n"); 489 | 490 | const char *expected_str = expected_fstring.get(); 491 | 492 | std::vector expected_calls; 493 | expected_calls.push_back({ CalledFunc::PreOp, 0 }); 494 | for (const char *c = expected_str; *c; ++c) 495 | expected_calls.push_back({ CalledFunc::PutC, *c }); 496 | expected_calls.push_back({ CalledFunc::PostOp, 0 }); 497 | 498 | CHECK_EQUAL(e, r); 499 | CHECK_EQUAL(expected_calls.size(), FuncCallLog.size()); 500 | CHECK_ARRAY_EQUAL(expected_calls, FuncCallLog, FuncCallLog.size()); 501 | 502 | CHECK_EQUAL(expected_str, ostring.str()); 503 | CHECK_EQUAL(ostring.str().size(), r); 504 | } 505 | 506 | TEST_FIXTURE(StdIOFixture, PrintFManyManyArgsTest) 507 | { 508 | // On X64_86 first 6 args are passed in registers, rest on the stack. Using va_arg() generates a branch, which 509 | // is normally not taken by test suite - gives incomplete branch coverage. This test passes many arguments 510 | // in order to force the second branch to be taken - improve coverage rate. 511 | int r = fslc_fprintf(&stream, "Arg1: %d, Arg2: %d, Arg3: %d, Arg4: %d, Arg5: %d, Arg6: %u, Arg7: %lld, Arg8: %llu, Arg9: %s", 1, 2, 3, 4, 5, 6U, 17179869184LL, 17179869184LLU, "str"); 512 | int e = eprintf("Arg1: %d, Arg2: %d, Arg3: %d, Arg4: %d, Arg5: %d, Arg6: %u, Arg7: %lld, Arg8: %llu, Arg9: %s", 1, 2, 3, 4, 5, 6U, 17179869184LL, 17179869184LLU, "str"); 513 | 514 | CHECK_EQUAL(e, r); 515 | CHECK_EQUAL(expected_fstring.get(), ostring.str()); 516 | CHECK_EQUAL(ostring.str().size(), r); 517 | } 518 | } 519 | --------------------------------------------------------------------------------