diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index b13817ae8f..54e71ae96d 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -253,7 +253,7 @@ const int TIM_DIV265 __attribute__((deprecated, weak)) = TIM_DIV256; #ifdef __cplusplus #include -#include "pgmspace.h" +#include #include "WCharacter.h" #include "WString.h" diff --git a/cores/esp8266/libc_replacements.c b/cores/esp8266/libc_replacements.c index fc6c2f142d..be55e49d3d 100644 --- a/cores/esp8266/libc_replacements.c +++ b/cores/esp8266/libc_replacements.c @@ -128,4 +128,4 @@ void _exit(int status) { int atexit(void (*func)()) { (void) func; return 0; -} +} \ No newline at end of file diff --git a/cores/esp8266/pgmspace.cpp b/cores/esp8266/pgmspace.cpp deleted file mode 100644 index f3c376dcab..0000000000 --- a/cores/esp8266/pgmspace.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* - pgmspace.cpp - string functions that support PROGMEM - Copyright (c) 2015 Michael C. Miller. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include "pgmspace.h" - -extern "C" { - -size_t strnlen_P(PGM_P s, size_t size) { - const char* cp; - for (cp = s; size != 0 && pgm_read_byte(cp) != '\0'; cp++, size--); - return (size_t) (cp - s); -} - -char* strstr_P(const char* haystack, PGM_P needle) -{ - const char* pn = reinterpret_cast(needle); - if (haystack[0] == 0) { - if (pgm_read_byte(pn)) { - return NULL; - } - return (char*) haystack; - } - - while (*haystack) { - size_t i = 0; - while (true) { - char n = pgm_read_byte(pn + i); - if (n == 0) { - return (char *) haystack; - } - if (n != haystack[i]) { - break; - } - ++i; - } - ++haystack; - } - return NULL; -} - -void* memcpy_P(void* dest, PGM_VOID_P src, size_t count) { - const uint8_t* read = reinterpret_cast(src); - uint8_t* write = reinterpret_cast(dest); - - while (count) - { - *write++ = pgm_read_byte(read++); - count--; - } - - return dest; -} - -int memcmp_P(const void* buf1, PGM_VOID_P buf2P, size_t size) { - int result = 0; - const uint8_t* read1 = (const uint8_t*)buf1; - const uint8_t* read2 = (const uint8_t*)buf2P; - - while (size > 0) { - uint8_t ch2 = pgm_read_byte(read2); - uint8_t ch1 = *read1; - if (ch1 != ch2) { - result = (int)(ch1)-(int)(ch2); - break; - } - - read1++; - read2++; - size--; - } - - return result; -} - -void* memccpy_P(void* dest, PGM_VOID_P src, int c, size_t count) { - uint8_t* read = (uint8_t*)src; - uint8_t* write = (uint8_t*)dest; - void* result = NULL; - - while (count > 0) { - uint8_t ch = pgm_read_byte(read++); - *write++ = ch; - count--; - if (c == ch) { - return write; // the value after the found c - } - } - - return result; -} - -void* memmem_P(const void* buf, size_t bufSize, PGM_VOID_P findP, size_t findPSize) { - const uint8_t* read = (const uint8_t*)buf; - const uint8_t* find = (uint8_t*)findP; - uint8_t first = pgm_read_byte(find++); - - findPSize--; - - while (bufSize > 0) { - if (*read == first) { - size_t findSize = findPSize; - const uint8_t* tag = read + 1; - size_t tagBufSize = bufSize - 1; - const uint8_t* findTag = find; - - while (tagBufSize > 0 && findSize > 0) { - uint8_t ch = pgm_read_byte(findTag++); - if (ch != *tag) { - bufSize--; - read++; - break; - } - findSize--; - tagBufSize--; - tag++; - } - if (findSize == 0) { - return (void*)read; - } - } - else { - bufSize--; - read++; - } - } - return NULL; -} - - -char* strncpy_P(char* dest, PGM_P src, size_t size) { - bool size_known = (size != SIZE_IRRELEVANT); - const char* read = src; - char* write = dest; - char ch = '.'; - while (size > 0 && ch != '\0') - { - ch = pgm_read_byte(read++); - *write++ = ch; - size--; - } - if (size_known) - { - while (size > 0) - { - *write++ = 0; - size--; - } - } - - return dest; -} - -char* strncat_P(char* dest, PGM_P src, size_t size) { - char* write = dest; - - while (*write != '\0') - { - write++; - } - - const char* read = src; - char ch = '.'; - - while (size > 0 && ch != '\0') - { - ch = pgm_read_byte(read++); - *write++ = ch; - - size--; - } - - if (ch != '\0') - { - *write = '\0'; - } - - return dest; -} - -int strncmp_P(const char* str1, PGM_P str2P, size_t size) { - int result = 0; - - while (size > 0) - { - char ch1 = *str1++; - char ch2 = pgm_read_byte(str2P++); - result = ch1 - ch2; - if (result != 0 || ch2 == '\0') - { - break; - } - - size--; - } - - return result; -} - -int strncasecmp_P(const char* str1, PGM_P str2P, size_t size) { - int result = 0; - - while (size > 0) - { - char ch1 = tolower(*str1++); - char ch2 = tolower(pgm_read_byte(str2P++)); - result = ch1 - ch2; - if (result != 0 || ch2 == '\0') - { - break; - } - - size--; - } - - return result; -} - -int printf_P(PGM_P formatP, ...) { - int ret; - va_list arglist; - va_start(arglist, formatP); - - size_t fmtLen = strlen_P(formatP); - char* format = new char[fmtLen + 1]; - strcpy_P(format, formatP); - - ret = vprintf(format, arglist); - - delete[] format; - - va_end(arglist); - return ret; -} - -int sprintf_P(char* str, PGM_P formatP, ...) { - int ret; - va_list arglist; - va_start(arglist, formatP); - - ret = vsnprintf_P(str, SIZE_IRRELEVANT, formatP, arglist); - - va_end(arglist); - return ret; -} - -int snprintf_P(char* str, size_t strSize, PGM_P formatP, ...) { - int ret; - va_list arglist; - va_start(arglist, formatP); - - ret = vsnprintf_P(str, strSize, formatP, arglist); - - va_end(arglist); - return ret; -} - -int vsnprintf_P(char* str, size_t strSize, PGM_P formatP, va_list ap) { - int ret; - - size_t fmtLen = strlen_P(formatP); - char* format = new char[fmtLen + 1]; - strcpy_P(format, formatP); - - ret = vsnprintf(str, strSize, format, ap); - - delete[] format; - - return ret; -} - -} // extern "C" diff --git a/cores/esp8266/pgmspace.h b/cores/esp8266/pgmspace.h index 2b9c3d6b02..af1a211a3f 100644 --- a/cores/esp8266/pgmspace.h +++ b/cores/esp8266/pgmspace.h @@ -1,163 +1,14 @@ -#ifndef __PGMSPACE_H_ -#define __PGMSPACE_H_ +// pgmspace.h stub -#include -#include +// This file's contents have been moved to newlib. This file simply +// includes the newlib pgmspace file as well as some ets headers +// to preserve backwards compatibility +#include #ifdef __ets__ #include "ets_sys.h" #include "osapi.h" -// Since __section__ is supposed to be only use for global variables, -// there could be conflicts when a static/inlined function has them in the -// same file as a non-static PROGMEM object. -// Ref: https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html -// Place each progmem object into its own named section, avoiding conflicts - -// The following two macros cause a parameter to be enclosed in quotes -// by the preopressor (i.e. for concatenating ints to strings) -#define __STRINGIZE_NX(A) #A -#define __STRINGIZE(A) __STRINGIZE_NX(A) - -#define PROGMEM __attribute__((section( "\".irom.text." __FILE__ "." __STRINGIZE(__LINE__) "." __STRINGIZE(__COUNTER__) "\""))) - -#define PGM_P const char * -#define PGM_VOID_P const void * -#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) -#else //__ets__ -#define PROGMEM -#define PGM_P const char * -#define PGM_VOID_P const void * -#define PSTR(s) (s) - -#endif // __ets__ - - -#ifdef __cplusplus -extern "C" { -#endif - -#define _SFR_BYTE(n) (n) - -#ifdef __PROG_TYPES_COMPAT__ - -typedef void prog_void; -typedef char prog_char; -typedef unsigned char prog_uchar; -typedef int8_t prog_int8_t; -typedef uint8_t prog_uint8_t; -typedef int16_t prog_int16_t; -typedef uint16_t prog_uint16_t; -typedef int32_t prog_int32_t; -typedef uint32_t prog_uint32_t; - -#endif // defined(__PROG_TYPES_COMPAT__) - -#define SIZE_IRRELEVANT 0x7fffffff - -// memchr_P and memrchr_P are not implemented due to danger in its use, and -// how uninteresting their use is -// since its a flash string, you should already know where the char is within it, -// further, it could return a pointer into the flash memory that is not 32bit aligned -// which could cause an exception if read -// PGM_VOID_P memchr_P(PGM_VOID_P bufP, int c, size_t count); -// PGM_VOID_P memrchr_P(PGM_VOID_P bufP, int c, size_t count); - -int memcmp_P(const void* buf1, PGM_VOID_P buf2P, size_t size); -// memccpy_P is only valid when used with pointers to 8bit data, due to size aligned pointers -// and endianess of the values greater than 8bit, matching c may return invalid aligned pointers -void* memccpy_P(void* dest, PGM_VOID_P src, int c, size_t count); -void* memmem_P(const void* buf, size_t bufSize, PGM_VOID_P findP, size_t findPSize); -void* memcpy_P(void* dest, PGM_VOID_P src, size_t count); - -char* strncpy_P(char* dest, PGM_P src, size_t size); -#define strcpy_P(dest, src) strncpy_P((dest), (src), SIZE_IRRELEVANT) - -char* strncat_P(char* dest, PGM_P src, size_t size); -#define strcat_P(dest, src) strncat_P((dest), (src), SIZE_IRRELEVANT) - -int strncmp_P(const char* str1, PGM_P str2P, size_t size); -#define strcmp_P(str1, str2P) strncmp_P((str1), (str2P), SIZE_IRRELEVANT) - -int strncasecmp_P(const char* str1, PGM_P str2P, size_t size); -#define strcasecmp_P(str1, str2P) strncasecmp_P((str1), (str2P), SIZE_IRRELEVANT) - -size_t strnlen_P(PGM_P s, size_t size); -#define strlen_P(strP) strnlen_P((strP), SIZE_IRRELEVANT) - -char* strstr_P(const char* haystack, PGM_P needle); - -int printf_P(PGM_P formatP, ...) __attribute__((format(printf, 1, 2))); -int sprintf_P(char *str, PGM_P formatP, ...) __attribute__((format(printf, 2, 3))); -int snprintf_P(char *str, size_t strSize, PGM_P formatP, ...) __attribute__((format(printf, 3, 4))); -int vsnprintf_P(char *str, size_t strSize, PGM_P formatP, va_list ap) __attribute__((format(printf, 3, 0))); - -// flash memory must be read using 32 bit aligned addresses else a processor -// exception will be triggered -// order within the 32 bit values are -// -------------- -// b3, b2, b1, b0 -// w1, w0 - -#ifdef __ets__ - -#define pgm_read_with_offset(addr, res) \ - asm("extui %0, %1, 0, 2\n" /* Extract offset within word (in bytes) */ \ - "sub %1, %1, %0\n" /* Subtract offset from addr, yielding an aligned address */ \ - "l32i.n %1, %1, 0x0\n" /* Load word from aligned address */ \ - "slli %0, %0, 3\n" /* Mulitiply offset by 8, yielding an offset in bits */ \ - "ssr %0\n" /* Prepare to shift by offset (in bits) */ \ - "srl %0, %1\n" /* Shift right; now the requested byte is the first one */ \ - :"=r"(res), "=r"(addr) \ - :"1"(addr) \ - :); - -static inline uint8_t pgm_read_byte_inlined(const void* addr) { - register uint32_t res; - pgm_read_with_offset(addr, res); - return (uint8_t) res; /* This masks the lower byte from the returned word */ -} - -/* Although this says "word", it's actually 16 bit, i.e. half word on Xtensa */ -static inline uint16_t pgm_read_word_inlined(const void* addr) { - register uint32_t res; - pgm_read_with_offset(addr, res); - return (uint16_t) res; /* This masks the lower half-word from the returned word */ -} - -// Make sure, that libraries checking existence of this macro are not failing -#ifdef __PROG_TYPES_COMPAT__ -#define pgm_read_byte(addr) pgm_read_byte_inlined((const void*)(addr)) -#define pgm_read_word(addr) pgm_read_word_inlined((const void*)(addr)) -#else -#define pgm_read_byte(addr) pgm_read_byte_inlined(addr) -#define pgm_read_word(addr) pgm_read_word_inlined(addr) -#endif - -#else //__ets__ -#define pgm_read_byte(addr) (*reinterpret_cast(addr)) -#define pgm_read_word(addr) (*reinterpret_cast(addr)) -#endif //__ets__ - -#define pgm_read_dword(addr) (*reinterpret_cast(addr)) -#define pgm_read_float(addr) (*reinterpret_cast(addr)) -#define pgm_read_ptr(addr) (*reinterpret_cast(addr)) - -#define pgm_read_byte_near(addr) pgm_read_byte(addr) -#define pgm_read_word_near(addr) pgm_read_word(addr) -#define pgm_read_dword_near(addr) pgm_read_dword(addr) -#define pgm_read_float_near(addr) pgm_read_float(addr) -#define pgm_read_ptr_near(addr) pgm_read_ptr(addr) -#define pgm_read_byte_far(addr) pgm_read_byte(addr) -#define pgm_read_word_far(addr) pgm_read_word(addr) -#define pgm_read_dword_far(addr) pgm_read_dword(addr) -#define pgm_read_float_far(addr) pgm_read_float(addr) -#define pgm_read_ptr_far(addr) pgm_read_ptr(addr) - -#ifdef __cplusplus -} #endif - -#endif //__PGMSPACE_H_ diff --git a/tests/device/test_libc/libm_string.c b/tests/device/test_libc/libm_string.c new file mode 100644 index 0000000000..17f29098cd --- /dev/null +++ b/tests/device/test_libc/libm_string.c @@ -0,0 +1,575 @@ +#include +#include +#include +#include + + + +#define memcmp memcmp_P +#define memcpy memcpy_P +#define memmem memmem_P +#define memchr memchr_P +#define strcat strcat_P +#define strncat strncat_P +#define strcpy strcpy_P +#define strncpy strncpy_P +#define strlen strlen_P +#define strnlen strnlen_P +#define strcmp strcmp_P +#define strncmp strncmp_P + + +_CONST char *it = ""; /* Routine name for message routines. */ +static int errors = 0; + +/* Complain if condition is not true. */ +#define check(thing) checkit(thing, __LINE__) + +static void +_DEFUN(checkit,(ok,l), + int ok _AND + int l ) + +{ +// newfunc(it); +// line(l); + + if (!ok) + { + printf("string.c:%d %s\n", l, it); + ++errors; + } +} + + + +/* Complain if first two args don't strcmp as equal. */ +#define equal(a, b) funcqual(a,b,__LINE__); + +static void +_DEFUN(funcqual,(a,b,l), + char *a _AND + char *b _AND + int l) +{ +// newfunc(it); + +// line(l); + if (a == NULL && b == NULL) return; + if (strcmp(a,b)) { + printf("string.c:%d (%s)\n", l, it); + } +} + + + +static char one[50]; +static char two[50]; + + +void libm_test_string() +{ + /* Test strcmp first because we use it to test other things. */ + it = "strcmp"; + check(strcmp("", "") == 0); /* Trivial case. */ + check(strcmp("a", "a") == 0); /* Identity. */ + check(strcmp("abc", "abc") == 0); /* Multicharacter. */ + check(strcmp("abc", "abcd") < 0); /* Length mismatches. */ + check(strcmp("abcd", "abc") > 0); + check(strcmp("abcd", "abce") < 0); /* Honest miscompares. */ + check(strcmp("abce", "abcd") > 0); + check(strcmp("a\103", "a") > 0); /* Tricky if char signed. */ + check(strcmp("a\103", "a\003") > 0); + + /* Test strcpy next because we need it to set up other tests. */ + it = "strcpy"; + check(strcpy(one, "abcd") == one); /* Returned value. */ + equal(one, "abcd"); /* Basic test. */ + + (void) strcpy(one, "x"); + equal(one, "x"); /* Writeover. */ + equal(one+2, "cd"); /* Wrote too much? */ + + (void) strcpy(two, "hi there"); + (void) strcpy(one, two); + equal(one, "hi there"); /* Basic test encore. */ + equal(two, "hi there"); /* Stomped on source? */ + + (void) strcpy(one, ""); + equal(one, ""); /* Boundary condition. */ + + /* strcat. */ + it = "strcat"; + (void) strcpy(one, "ijk"); + check(strcat(one, "lmn") == one); /* Returned value. */ + equal(one, "ijklmn"); /* Basic test. */ + + (void) strcpy(one, "x"); + (void) strcat(one, "yz"); + equal(one, "xyz"); /* Writeover. */ + equal(one+4, "mn"); /* Wrote too much? */ + + (void) strcpy(one, "gh"); + (void) strcpy(two, "ef"); + (void) strcat(one, two); + equal(one, "ghef"); /* Basic test encore. */ + equal(two, "ef"); /* Stomped on source? */ + + (void) strcpy(one, ""); + (void) strcat(one, ""); + equal(one, ""); /* Boundary conditions. */ + (void) strcpy(one, "ab"); + (void) strcat(one, ""); + equal(one, "ab"); + (void) strcpy(one, ""); + (void) strcat(one, "cd"); + equal(one, "cd"); + + /* strncat - first test it as strcat, with big counts, + then test the count mechanism. */ + it = "strncat"; + (void) strcpy(one, "ijk"); + check(strncat(one, "lmn", 99) == one); /* Returned value. */ + equal(one, "ijklmn"); /* Basic test. */ + + (void) strcpy(one, "x"); + (void) strncat(one, "yz", 99); + equal(one, "xyz"); /* Writeover. */ + equal(one+4, "mn"); /* Wrote too much? */ + + (void) strcpy(one, "gh"); + (void) strcpy(two, "ef"); + (void) strncat(one, two, 99); + equal(one, "ghef"); /* Basic test encore. */ + equal(two, "ef"); /* Stomped on source? */ + + (void) strcpy(one, ""); + (void) strncat(one, "", 99); + equal(one, ""); /* Boundary conditions. */ + (void) strcpy(one, "ab"); + (void) strncat(one, "", 99); + equal(one, "ab"); + (void) strcpy(one, ""); + (void) strncat(one, "cd", 99); + equal(one, "cd"); + + (void) strcpy(one, "ab"); + (void) strncat(one, "cdef", 2); + equal(one, "abcd"); /* Count-limited. */ + + (void) strncat(one, "gh", 0); + equal(one, "abcd"); /* Zero count. */ + + (void) strncat(one, "gh", 2); + equal(one, "abcdgh"); /* Count _AND length equal. */ + it = "strncmp"; + /* strncmp - first test as strcmp with big counts";*/ + check(strncmp("", "", 99) == 0); /* Trivial case. */ + check(strncmp("a", "a", 99) == 0); /* Identity. */ + check(strncmp("abc", "abc", 99) == 0); /* Multicharacter. */ + check(strncmp("abc", "abcd", 99) < 0); /* Length unequal. */ + check(strncmp("abcd", "abc",99) > 0); + check(strncmp("abcd", "abce", 99) < 0); /* Honestly unequal. */ + check(strncmp("abce", "abcd",99)>0); + check(strncmp("abce", "abcd", 3) == 0); /* Count limited. */ + check(strncmp("abce", "abc", 3) == 0); /* Count == length. */ + check(strncmp("abcd", "abce", 4) < 0); /* Nudging limit. */ + check(strncmp("abc", "def", 0) == 0); /* Zero count. */ + + /* strncpy - testing is a bit different because of odd semantics. */ + it = "strncpy"; + check(strncpy(one, "abc", 4) == one); /* Returned value. */ + equal(one, "abc"); /* Did the copy go right? */ + + (void) strcpy(one, "abcdefgh"); + (void) strncpy(one, "xyz", 2); + equal(one, "xycdefgh"); /* Copy cut by count. */ + + (void) strcpy(one, "abcdefgh"); + (void) strncpy(one, "xyz", 3); /* Copy cut just before NUL. */ + equal(one, "xyzdefgh"); + + (void) strcpy(one, "abcdefgh"); + (void) strncpy(one, "xyz", 4); /* Copy just includes NUL. */ + equal(one, "xyz"); + equal(one+4, "efgh"); /* Wrote too much? */ + + (void) strcpy(one, "abcdefgh"); + (void) strncpy(one, "xyz", 5); /* Copy includes padding. */ + equal(one, "xyz"); + equal(one+4, ""); + equal(one+5, "fgh"); + + (void) strcpy(one, "abc"); + (void) strncpy(one, "xyz", 0); /* Zero-length copy. */ + equal(one, "abc"); + + (void) strncpy(one, "", 2); /* Zero-length source. */ + equal(one, ""); + equal(one+1, ""); + equal(one+2, "c"); + + (void) strcpy(one, "hi there"); + (void) strncpy(two, one, 9); + equal(two, "hi there"); /* Just paranoia. */ + equal(one, "hi there"); /* Stomped on source? */ + + /* strlen. */ + it = "strlen"; + check(strlen("") == 0); /* Empty. */ + check(strlen("a") == 1); /* Single char. */ + check(strlen("abcd") == 4); /* Multiple chars. */ + + /* strchr. */ + it = "strchr"; + check(strchr("abcd", 'z') == NULL); /* Not found. */ + (void) strcpy(one, "abcd"); + check(strchr(one, 'c') == one+2); /* Basic test. */ + check(strchr(one, 'd') == one+3); /* End of string. */ + check(strchr(one, 'a') == one); /* Beginning. */ + check(strchr(one, '\0') == one+4); /* Finding NUL. */ + (void) strcpy(one, "ababa"); + check(strchr(one, 'b') == one+1); /* Finding first. */ + (void) strcpy(one, ""); + check(strchr(one, 'b') == NULL); /* Empty string. */ + check(strchr(one, '\0') == one); /* NUL in empty string. */ + + /* index - just like strchr. */ + it = "index"; + check(index("abcd", 'z') == NULL); /* Not found. */ + (void) strcpy(one, "abcd"); + check(index(one, 'c') == one+2); /* Basic test. */ + check(index(one, 'd') == one+3); /* End of string. */ + check(index(one, 'a') == one); /* Beginning. */ + check(index(one, '\0') == one+4); /* Finding NUL. */ + (void) strcpy(one, "ababa"); + check(index(one, 'b') == one+1); /* Finding first. */ + (void) strcpy(one, ""); + check(index(one, 'b') == NULL); /* Empty string. */ + check(index(one, '\0') == one); /* NUL in empty string. */ + + /* strrchr. */ + it = "strrchr"; + check(strrchr("abcd", 'z') == NULL); /* Not found. */ + (void) strcpy(one, "abcd"); + check(strrchr(one, 'c') == one+2); /* Basic test. */ + check(strrchr(one, 'd') == one+3); /* End of string. */ + check(strrchr(one, 'a') == one); /* Beginning. */ + check(strrchr(one, '\0') == one+4); /* Finding NUL. */ + (void) strcpy(one, "ababa"); + check(strrchr(one, 'b') == one+3); /* Finding last. */ + (void) strcpy(one, ""); + check(strrchr(one, 'b') == NULL); /* Empty string. */ + check(strrchr(one, '\0') == one); /* NUL in empty string. */ + + /* rindex - just like strrchr. */ + it = "rindex"; + check(rindex("abcd", 'z') == NULL); /* Not found. */ + (void) strcpy(one, "abcd"); + check(rindex(one, 'c') == one+2); /* Basic test. */ + check(rindex(one, 'd') == one+3); /* End of string. */ + check(rindex(one, 'a') == one); /* Beginning. */ + check(rindex(one, '\0') == one+4); /* Finding NUL. */ + (void) strcpy(one, "ababa"); + check(rindex(one, 'b') == one+3); /* Finding last. */ + (void) strcpy(one, ""); + check(rindex(one, 'b') == NULL); /* Empty string. */ + check(rindex(one, '\0') == one); /* NUL in empty string. */ + + /* strpbrk - somewhat like strchr. */ + it = "strpbrk"; + check(strpbrk("abcd", "z") == NULL); /* Not found. */ + (void) strcpy(one, "abcd"); + check(strpbrk(one, "c") == one+2); /* Basic test. */ + check(strpbrk(one, "d") == one+3); /* End of string. */ + check(strpbrk(one, "a") == one); /* Beginning. */ + check(strpbrk(one, "") == NULL); /* Empty search list. */ + check(strpbrk(one, "cb") == one+1); /* Multiple search. */ + (void) strcpy(one, "abcabdea"); + check(strpbrk(one, "b") == one+1); /* Finding first. */ + check(strpbrk(one, "cb") == one+1); /* With multiple search. */ + check(strpbrk(one, "db") == one+1); /* Another variant. */ + (void) strcpy(one, ""); + check(strpbrk(one, "bc") == NULL); /* Empty string. */ + check(strpbrk(one, "") == NULL); /* Both strings empty. */ + + /* strstr - somewhat like strchr. */ + it = "strstr"; + check(strstr("z", "abcd") == NULL); /* Not found. */ + check(strstr("abx", "abcd") == NULL); /* Dead end. */ + (void) strcpy(one, "abcd"); + check(strstr(one,"c") == one+2); /* Basic test. */ + check(strstr(one, "bc") == one+1); /* Multichar. */ + check(strstr(one,"d") == one+3); /* End of string. */ + check(strstr(one,"cd") == one+2); /* Tail of string. */ + check(strstr(one,"abc") == one); /* Beginning. */ + check(strstr(one,"abcd") == one); /* Exact match. */ + check(strstr(one,"de") == NULL); /* Past end. */ + check(strstr(one,"") == one); /* Finding empty. */ + (void) strcpy(one, "ababa"); + check(strstr(one,"ba") == one+1); /* Finding first. */ + (void) strcpy(one, ""); + check(strstr(one, "b") == NULL); /* Empty string. */ + check(strstr(one,"") == one); /* Empty in empty string. */ + (void) strcpy(one, "bcbca"); + check(strstr(one,"bca") == one+2); /* False start. */ + (void) strcpy(one, "bbbcabbca"); + check(strstr(one,"bbca") == one+1); /* With overlap. */ + + /* strspn. */ + it = "strspn"; + check(strspn("abcba", "abc") == 5); /* Whole string. */ + check(strspn("abcba", "ab") == 2); /* Partial. */ + check(strspn("abc", "qx") == 0); /* None. */ + check(strspn("", "ab") == 0); /* Null string. */ + check(strspn("abc", "") == 0); /* Null search list. */ + + /* strcspn. */ + it = "strcspn"; + check(strcspn("abcba", "qx") == 5); /* Whole string. */ + check(strcspn("abcba", "cx") == 2); /* Partial. */ + check(strcspn("abc", "abc") == 0); /* None. */ + check(strcspn("", "ab") == 0); /* Null string. */ + check(strcspn("abc", "") == 3); /* Null search list. */ + + /* strtok - the hard one. */ + it = "strtok"; + (void) strcpy(one, "first, second, third"); + equal(strtok(one, ", "), "first"); /* Basic test. */ + equal(one, "first"); + equal(strtok((char *)NULL, ", "), "second"); + equal(strtok((char *)NULL, ", "), "third"); + check(strtok((char *)NULL, ", ") == NULL); + (void) strcpy(one, ", first, "); + equal(strtok(one, ", "), "first"); /* Extra delims, 1 tok. */ + check(strtok((char *)NULL, ", ") == NULL); + (void) strcpy(one, "1a, 1b; 2a, 2b"); + equal(strtok(one, ", "), "1a"); /* Changing delim lists. */ + equal(strtok((char *)NULL, "; "), "1b"); + equal(strtok((char *)NULL, ", "), "2a"); + (void) strcpy(two, "x-y"); + equal(strtok(two, "-"), "x"); /* New string before done. */ + equal(strtok((char *)NULL, "-"), "y"); + check(strtok((char *)NULL, "-") == NULL); + (void) strcpy(one, "a,b, c,, ,d"); + equal(strtok(one, ", "), "a"); /* Different separators. */ + equal(strtok((char *)NULL, ", "), "b"); + equal(strtok((char *)NULL, " ,"), "c"); /* Permute list too. */ + equal(strtok((char *)NULL, " ,"), "d"); + check(strtok((char *)NULL, ", ") == NULL); + check(strtok((char *)NULL, ", ") == NULL); /* Persistence. */ + (void) strcpy(one, ", "); + check(strtok(one, ", ") == NULL); /* No tokens. */ + (void) strcpy(one, ""); + check(strtok(one, ", ") == NULL); /* Empty string. */ + (void) strcpy(one, "abc"); + equal(strtok(one, ", "), "abc"); /* No delimiters. */ + check(strtok((char *)NULL, ", ") == NULL); + (void) strcpy(one, "abc"); + equal(strtok(one, ""), "abc"); /* Empty delimiter list. */ + check(strtok((char *)NULL, "") == NULL); + (void) strcpy(one, "abcdefgh"); + (void) strcpy(one, "a,b,c"); + equal(strtok(one, ","), "a"); /* Basics again... */ + equal(strtok((char *)NULL, ","), "b"); + equal(strtok((char *)NULL, ","), "c"); + check(strtok((char *)NULL, ",") == NULL); + equal(one+6, "gh"); /* Stomped past end? */ + equal(one, "a"); /* Stomped old tokens? */ + equal(one+2, "b"); + equal(one+4, "c"); + + /* memcmp. */ + it = "memcmp"; + check(memcmp("a", "a", 1) == 0); /* Identity. */ + check(memcmp("abc", "abc", 3) == 0); /* Multicharacter. */ + check(memcmp("abcd", "abce", 4) < 0); /* Honestly unequal. */ + check(memcmp("abce", "abcd",4)); + check(memcmp("alph", "beta", 4) < 0); + check(memcmp("abce", "abcd", 3) == 0); /* Count limited. */ + check(memcmp("abc", "def", 0) == 0); /* Zero count. */ + + /* memcmp should test strings as unsigned */ + one[0] = 0xfe; + two[0] = 0x03; + check(memcmp(one, two,1) > 0); + + + /* memchr. */ + it = "memchr"; + check(memchr("abcd", 'z', 4) == NULL); /* Not found. */ + (void) strcpy(one, "abcd"); + check(memchr(one, 'c', 4) == one+2); /* Basic test. */ + check(memchr(one, 'd', 4) == one+3); /* End of string. */ + check(memchr(one, 'a', 4) == one); /* Beginning. */ + check(memchr(one, '\0', 5) == one+4); /* Finding NUL. */ + (void) strcpy(one, "ababa"); + check(memchr(one, 'b', 5) == one+1); /* Finding first. */ + check(memchr(one, 'b', 0) == NULL); /* Zero count. */ + check(memchr(one, 'a', 1) == one); /* Singleton case. */ + (void) strcpy(one, "a\203b"); + check(memchr(one, 0203, 3) == one+1); /* Unsignedness. */ + + /* memcpy - need not work for overlap. */ + it = "memcpy"; + check(memcpy(one, "abc", 4) == one); /* Returned value. */ + equal(one, "abc"); /* Did the copy go right? */ + + (void) strcpy(one, "abcdefgh"); + (void) memcpy(one+1, "xyz", 2); + equal(one, "axydefgh"); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) memcpy(one, "xyz", 0); + equal(one, "abc"); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) memcpy(two, one, 9); + equal(two, "hi there"); /* Just paranoia. */ + equal(one, "hi there"); /* Stomped on source? */ +#if 0 + /* memmove - must work on overlap. */ + it = "memmove"; + check(memmove(one, "abc", 4) == one); /* Returned value. */ + equal(one, "abc"); /* Did the copy go right? */ + + (void) strcpy(one, "abcdefgh"); + (void) memmove(one+1, "xyz", 2); + equal(one, "axydefgh"); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) memmove(one, "xyz", 0); + equal(one, "abc"); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) memmove(two, one, 9); + equal(two, "hi there"); /* Just paranoia. */ + equal(one, "hi there"); /* Stomped on source? */ + + (void) strcpy(one, "abcdefgh"); + (void) memmove(one+1, one, 9); + equal(one, "aabcdefgh"); /* Overlap, right-to-left. */ + + (void) strcpy(one, "abcdefgh"); + (void) memmove(one+1, one+2, 7); + equal(one, "acdefgh"); /* Overlap, left-to-right. */ + + (void) strcpy(one, "abcdefgh"); + (void) memmove(one, one, 9); + equal(one, "abcdefgh"); /* 100% overlap. */ +#endif +#if 0 + /* memccpy - first test like memcpy, then the search part + The SVID, the only place where memccpy is mentioned, says + overlap might fail, so we don't try it. Besides, it's hard + to see the rationale for a non-left-to-right memccpy. */ + it = "memccpy"; + check(memccpy(one, "abc", 'q', 4) == NULL); /* Returned value. */ + equal(one, "abc"); /* Did the copy go right? */ + + (void) strcpy(one, "abcdefgh"); + (void) memccpy(one+1, "xyz", 'q', 2); + equal(one, "axydefgh"); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) memccpy(one, "xyz", 'q', 0); + equal(one, "abc"); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) memccpy(two, one, 'q', 9); + equal(two, "hi there"); /* Just paranoia. */ + equal(one, "hi there"); /* Stomped on source? */ + + (void) strcpy(one, "abcdefgh"); + (void) strcpy(two, "horsefeathers"); + check(memccpy(two, one, 'f', 9) == two+6); /* Returned value. */ + equal(one, "abcdefgh"); /* Source intact? */ + equal(two, "abcdefeathers"); /* Copy correct? */ + + (void) strcpy(one, "abcd"); + (void) strcpy(two, "bumblebee"); + check(memccpy(two, one, 'a', 4) == two+1); /* First char. */ + equal(two, "aumblebee"); + check(memccpy(two, one, 'd', 4) == two+4); /* Last char. */ + equal(two, "abcdlebee"); + (void) strcpy(one, "xyz"); + check(memccpy(two, one, 'x', 1) == two+1); /* Singleton. */ + equal(two, "xbcdlebee"); +#endif + /* memset. */ + it = "memset"; + (void) strcpy(one, "abcdefgh"); + check(memset(one+1, 'x', 3) == one+1); /* Return value. */ + equal(one, "axxxefgh"); /* Basic test. */ + + (void) memset(one+2, 'y', 0); + equal(one, "axxxefgh"); /* Zero-length set. */ + + (void) memset(one+5, 0, 1); + equal(one, "axxxe"); /* Zero fill. */ + equal(one+6, "gh"); /* _AND the leftover. */ + + (void) memset(one+2, 010045, 1); + equal(one, "ax\045xe"); /* Unsigned char convert. */ + + /* bcopy - much like memcpy. + Berklix manual is silent about overlap, so don't test it. */ + it = "bcopy"; + (void) bcopy("abc", one, 4); + equal(one, "abc"); /* Simple copy. */ + + (void) strcpy(one, "abcdefgh"); + (void) bcopy("xyz", one+1, 2); + equal(one, "axydefgh"); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) bcopy("xyz", one, 0); + equal(one, "abc"); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) bcopy(one, two, 9); + equal(two, "hi there"); /* Just paranoia. */ + equal(one, "hi there"); /* Stomped on source? */ + + /* bzero. */ + it = "bzero"; + (void) strcpy(one, "abcdef"); + bzero(one+2, 2); + equal(one, "ab"); /* Basic test. */ + equal(one+3, ""); + equal(one+4, "ef"); + + (void) strcpy(one, "abcdef"); + bzero(one+2, 0); + equal(one, "abcdef"); /* Zero-length copy. */ + + /* bcmp - somewhat like memcmp. */ + it = "bcmp"; + check(bcmp("a", "a", 1) == 0); /* Identity. */ + check(bcmp("abc", "abc", 3) == 0); /* Multicharacter. */ + check(bcmp("abcd", "abce", 4) != 0); /* Honestly unequal. */ + check(bcmp("abce", "abcd",4)); + check(bcmp("alph", "beta", 4) != 0); + check(bcmp("abce", "abcd", 3) == 0); /* Count limited. */ + check(bcmp("abc", "def", 0) == 0); /* Zero count. */ + + if (errors) abort(); + printf("ok\n"); + +#if 0 /* strerror - VERY system-dependent. */ +{ + extern CONST unsigned int _sys_nerr; + extern CONST char *CONST _sys_errlist[]; + int f; + it = "strerror"; + f = open("/", O_WRONLY); /* Should always fail. */ + check(f < 0 && errno > 0 && errno < _sys_nerr); + equal(strerror(errno), _sys_errlist[errno]); +} +#endif +} + diff --git a/tests/device/test_libc/memcpy-1.c b/tests/device/test_libc/memcpy-1.c new file mode 100644 index 0000000000..e6b6384521 --- /dev/null +++ b/tests/device/test_libc/memcpy-1.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2011 ARM Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + + +#define memcmp memcmp_P +#define memcpy memcpy_P +#define memmem memmem_P +#define memchr memchr_P +#define strcat strcat_P +#define strncat strncat_P +#define strcpy strcpy_P +#define strncpy strncpy_P +#define strlen strlen_P +#define strnlen strnlen_P +#define strcmp strcmp_P +#define strncmp strncmp_P +#define BUFF_SIZE 512 + +#ifndef BUFF_SIZE +#define BUFF_SIZE 1024 +#endif + +#ifndef START_COPY +#define START_COPY 256 +#endif + +#ifndef MAX_BLOCK_SIZE +#define MAX_BLOCK_SIZE 128 +#endif + +#ifndef MAX_OFFSET +#define MAX_OFFSET 3 +#endif + +#if (START_COPY + MAX_OFFSET + MAX_BLOCK_SIZE >= BUFF_SIZE) +#error "Buffer overrun: START_COPY + MAX_OFFSET + MAX_BLOCK_SIZE >= BUFF_SIZE." +#endif + +#define TOO_MANY_ERRORS 11 +static int errors = 0; + +static void +print_error (char const* msg, ...) +{ + errors++; + if (errors == TOO_MANY_ERRORS) + { + fprintf (stderr, "Too many errors.\n"); + } + else if (errors < TOO_MANY_ERRORS) + { + va_list ap; + va_start (ap, msg); + vfprintf (stderr, msg, ap); + va_end (ap); + } + else + { + /* Further errors omitted. */ + } +} + +extern int rand_seed; +void memcpy_main(void) +{ + /* Allocate buffers to read and write from. */ + char src[BUFF_SIZE], dest[BUFF_SIZE], backup_src[BUFF_SIZE]; + + /* Fill the source buffer with non-null values, reproducable random data. */ + srand (rand_seed); + int i, j; + unsigned sa; + unsigned da; + unsigned n; + for (i = 0; i < BUFF_SIZE; i++) + { + src[i] = (char)rand () | 1; + backup_src[i] = src[i]; + } + + /* Make calls to memcpy with block sizes ranging between 1 and + MAX_BLOCK_SIZE bytes, aligned and misaligned source and destination. */ + for (sa = 0; sa <= MAX_OFFSET; sa++) + for (da = 0; da <= MAX_OFFSET; da++) + for (n = 1; n <= MAX_BLOCK_SIZE; n++) + { + //printf ("."); + /* Zero dest so we can check it properly after the copying. */ + for (j = 0; j < BUFF_SIZE; j++) + dest[j] = 0; + + void *ret = memcpy (dest + START_COPY + da, src + sa, n); + + /* Check return value. */ + if (ret != (dest + START_COPY + da)) + print_error ("\nFailed: wrong return value in memcpy of %u bytes " + "with src_align %u and dst_align %u. " + "Return value and dest should be the same" + "(ret is %p, dest is %p)\n", + n, sa, da, ret, dest + START_COPY + da); + + /* Check that content of the destination buffer + is the same as the source buffer, and + memory outside destination buffer is not modified. */ + for (j = 0; j < BUFF_SIZE; j++) + if ((unsigned)j < START_COPY + da) + { + if (dest[j] != 0) + print_error ("\nFailed: after memcpy of %u bytes " + "with src_align %u and dst_align %u, " + "byte %u before the start of dest is not 0.\n", + n, sa, da, START_COPY - j); + } + else if ((unsigned)j < START_COPY + da + n) + { + i = j - START_COPY - da; + if (dest[j] != (src + sa)[i]) + print_error ("\nFailed: after memcpy of %u bytes " + "with src_align %u and dst_align %u, " + "byte %u in dest and src are not the same.\n", + n, sa, da, i); + } + else if (dest[j] != 0) + { + print_error ("\nFailed: after memcpy of %u bytes " + "with src_align %u and dst_align %u, " + "byte %u after the end of dest is not 0.\n", + n, sa, da, j - START_COPY - da - n); + } + + /* Check src is not modified. */ + for (j = 0; j < BUFF_SIZE; j++) + if (src[i] != backup_src[i]) + print_error ("\nFailed: after memcpy of %u bytes " + "with src_align %u and dst_align %u, " + "byte %u of src is modified.\n", + n, sa, da, j); + } + + if (errors != 0) + abort (); + + printf("ok\n"); +} diff --git a/tests/device/test_libc/memmove1.c b/tests/device/test_libc/memmove1.c new file mode 100644 index 0000000000..f64feae759 --- /dev/null +++ b/tests/device/test_libc/memmove1.c @@ -0,0 +1,194 @@ +/* A minor test-program for memmove. + Copyright (C) 2005 Axis Communications. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Neither the name of Axis Communications nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AXIS COMMUNICATIONS AND ITS CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AXIS + COMMUNICATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +/* Test moves of 0..MAX bytes; overlapping-src-higher, + overlapping-src-lower and non-overlapping. The overlap varies with + 1..N where N is the size moved. This means an order of MAX**2 + iterations. The size of an octet may seem appropriate for MAX and + makes an upper limit for simple testing. For the CRIS simulator, + making this 256 added 90s to the test-run (2GHz P4) while 64 (4s) was + enough to spot the bugs that had crept in, hence the number chosen. */ +#define MAX 64 + +#include +#include +#include + +#define memcmp memcmp_P +#define memcpy memcpy_P +#define memmem memmem_P +#define memchr memchr_P +#define strcat strcat_P +#define strncat strncat_P +#define strcpy strcpy_P +#define strncpy strncpy_P +#define strlen strlen_P +#define strnlen strnlen_P +#define strcmp strcmp_P +#define strncmp strncmp_P + +#define TOO_MANY_ERRORS 11 +int errors = 0; + +#define DEBUGP \ + if (errors == TOO_MANY_ERRORS) \ + printf ("Further errors omitted\n"); \ + else if (errors < TOO_MANY_ERRORS) \ + printf + +/* A safe target-independent memmove. */ + +void +mymemmove (unsigned char *dest, unsigned char *src, size_t n) +{ + if ((src <= dest && src + n <= dest) + || src >= dest) + while (n-- > 0) + *dest++ = *src++; + else + { + dest += n; + src += n; + while (n-- > 0) + *--dest = *--src; + } +} + +/* It's either the noinline attribute or forcing the test framework to + pass -fno-builtin-memmove. */ +void +xmemmove (unsigned char *dest, unsigned char *src, size_t n) + __attribute__ ((__noinline__)); + +void +xmemmove (unsigned char *dest, unsigned char *src, size_t n) +{ + void *retp; + retp = memmove (dest, src, n); + + if (retp != dest) + { + errors++; + DEBUGP ("memmove of n bytes returned %p instead of dest=%p\n", + retp, dest); + } +} + + +/* Fill the array with something we can associate with a position, but + not exactly the same as the position index. */ + +void +fill (unsigned char dest[MAX*3]) +{ + size_t i; + for (i = 0; i < MAX*3; i++) + dest[i] = (10 + i) % MAX; +} + +void memmove_main(void) +{ + size_t i; + int errors = 0; + + /* Leave some room before and after the area tested, so we can detect + overwrites of up to N bytes, N being the amount tested. If you + want to test using valgrind, make these malloced instead. */ + unsigned char from_test[MAX*3]; + unsigned char to_test[MAX*3]; + unsigned char from_known[MAX*3]; + unsigned char to_known[MAX*3]; + + /* Non-overlap. */ + for (i = 0; i < MAX; i++) + { + /* Do the memmove first before setting the known array, so we know + it didn't change any of the known array. */ + fill (from_test); + fill (to_test); + xmemmove (to_test + MAX, 1 + from_test + MAX, i); + + fill (from_known); + fill (to_known); + mymemmove (to_known + MAX, 1 + from_known + MAX, i); + + if (memcmp (to_known, to_test, sizeof (to_known)) != 0) + { + errors++; + DEBUGP ("memmove failed non-overlap test for %d bytes\n", i); + } + } + + /* Overlap-from-before. */ + for (i = 0; i < MAX; i++) + { + size_t j; + for (j = 0; j < i; j++) + { + fill (to_test); + xmemmove (to_test + MAX * 2 - i, to_test + MAX * 2 - i - j, i); + + fill (to_known); + mymemmove (to_known + MAX * 2 - i, to_known + MAX * 2 - i - j, i); + + if (memcmp (to_known, to_test, sizeof (to_known)) != 0) + { + errors++; + DEBUGP ("memmove failed for %d bytes," + " with src %d bytes before dest\n", + i, j); + } + } + } + + /* Overlap-from-after. */ + for (i = 0; i < MAX; i++) + { + size_t j; + for (j = 0; j < i; j++) + { + fill (to_test); + xmemmove (to_test + MAX, to_test + MAX + j, i); + + fill (to_known); + mymemmove (to_known + MAX, to_known + MAX + j, i); + + if (memcmp (to_known, to_test, sizeof (to_known)) != 0) + { + errors++; + DEBUGP ("memmove failed when moving %d bytes," + " with src %d bytes after dest\n", + i, j); + } + } + } + + if (errors != 0) + abort (); + printf("ok\n"); +} diff --git a/tests/device/test_libc/strcmp-1.c b/tests/device/test_libc/strcmp-1.c new file mode 100644 index 0000000000..7eaede5e98 --- /dev/null +++ b/tests/device/test_libc/strcmp-1.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2011 ARM Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#define memcmp memcmp_P +#define memcpy memcpy_P +#define memmem memmem_P +#define memchr memchr_P +#define strcat strcat_P +#define strncat strncat_P +#define strcpy strcpy_P +#define strncpy strncpy_P +#define strlen strlen_P +#define strnlen strnlen_P +#define strcmp strcmp_P +#define strncmp strncmp_P + +#define BUFF_SIZE 256 + + +/* The macro LONG_TEST controls whether a short or a more comprehensive test + of strcmp should be performed. */ +#ifdef LONG_TEST +#ifndef BUFF_SIZE +#define BUFF_SIZE 1024 +#endif + +#ifndef MAX_BLOCK_SIZE +#define MAX_BLOCK_SIZE 128 +#endif + +#ifndef MAX_OFFSET +#define MAX_OFFSET 3 +#endif + +#ifndef MAX_DIFF +#define MAX_DIFF 8 +#endif + +#ifndef MAX_LEN +#define MAX_LEN 8 +#endif + +#ifndef MAX_ZEROS +#define MAX_ZEROS 8 +#endif +#else /* not defined LONG_TEST */ +#ifndef BUFF_SIZE +#define BUFF_SIZE 1024 +#endif + +#ifndef MAX_BLOCK_SIZE +#define MAX_BLOCK_SIZE 64 +#endif + +#ifndef MAX_OFFSET +#define MAX_OFFSET 3 +#endif + +#ifndef MAX_DIFF +#define MAX_DIFF 4 +#endif + +#ifndef MAX_LEN +#define MAX_LEN 4 +#endif + +#ifndef MAX_ZEROS +#define MAX_ZEROS 4 +#endif +#endif /* not defined LONG_TEST */ + +#if (MAX_OFFSET >= 26) +#error "MAX_OFFSET >= 26" +#endif +#if (MAX_OFFSET + MAX_BLOCK_SIZE + MAX_DIFF + MAX_LEN + MAX_ZEROS >= BUFF_SIZE) +#error "Buffer overrun: MAX_OFFSET + MAX_BLOCK_SIZE + MAX_DIFF + MAX_LEN + MAX_ZEROS >= BUFF_SIZE." +#endif + + +#define TOO_MANY_ERRORS 11 +static int errors = 0; + +const char *testname = "strcmp"; + +static void +print_error (char const* msg, ...) +{ + errors++; + if (errors == TOO_MANY_ERRORS) + { + fprintf (stderr, "Too many errors.\n"); + } + else if (errors < TOO_MANY_ERRORS) + { + va_list ap; + va_start (ap, msg); + vfprintf (stderr, msg, ap); + va_end (ap); + } + else + { + /* Further errors omitted. */ + } +} + + +extern int rand_seed; +void strcmp_main(void) +{ + /* Allocate buffers to read and write from. */ + char src[BUFF_SIZE], dest[BUFF_SIZE]; + + /* Fill the source buffer with non-null values, reproducable random data. */ + srand (rand_seed); + int i, j, zeros; + unsigned sa; + unsigned da; + unsigned n, m, len; + char *p; + int ret; + + /* Make calls to strcmp with block sizes ranging between 1 and + MAX_BLOCK_SIZE bytes, aligned and misaligned source and destination. */ + for (sa = 0; sa <= MAX_OFFSET; sa++) + for (da = 0; da <= MAX_OFFSET; da++) + for (n = 1; n <= MAX_BLOCK_SIZE; n++) + { + for (m = 1; m < n + MAX_DIFF; m++) + for (len = 0; len < MAX_LEN; len++) + for (zeros = 1; zeros < MAX_ZEROS; zeros++) + { + if (n - m > MAX_DIFF) + continue; + /* Make a copy of the source. */ + for (i = 0; i < BUFF_SIZE; i++) + { + src[i] = 'A' + (i % 26); + dest[i] = src[i]; + } + delay(0); + memcpy (dest + da, src + sa, n); + + /* Make src 0-terminated. */ + p = src + sa + n - 1; + for (i = 0; i < zeros; i++) + { + *p++ = '\0'; + } + + /* Modify dest. */ + p = dest + da + m - 1; + for (j = 0; j < (int)len; j++) + *p++ = 'x'; + /* Make dest 0-terminated. */ + *p = '\0'; + + ret = strcmp (src + sa, dest + da); + + /* Check return value. */ + if (n == m) + { + if (len == 0) + { + if (ret != 0) + { + print_error ("\nFailed: after %s of %u bytes " + "with src_align %u and dst_align %u, " + "dest after %d bytes is modified for %d bytes, " + "return value is %d, expected 0.\n", + testname, n, sa, da, m, len, ret); + } + } + else + { + if (ret >= 0) + print_error ("\nFailed: after %s of %u bytes " + "with src_align %u and dst_align %u, " + "dest after %d bytes is modified for %d bytes, " + "return value is %d, expected negative.\n", + testname, n, sa, da, m, len, ret); + } + } + else if (m > n) + { + if (ret >= 0) + { + print_error ("\nFailed: after %s of %u bytes " + "with src_align %u and dst_align %u, " + "dest after %d bytes is modified for %d bytes, " + "return value is %d, expected negative.\n", + testname, n, sa, da, m, len, ret); + } + } + else /* m < n */ + { + if (len == 0) + { + if (ret <= 0) + print_error ("\nFailed: after %s of %u bytes " + "with src_align %u and dst_align %u, " + "dest after %d bytes is modified for %d bytes, " + "return value is %d, expected positive.\n", + testname, n, sa, da, m, len, ret); + } + else + { + if (ret >= 0) + print_error ("\nFailed: after %s of %u bytes " + "with src_align %u and dst_align %u, " + "dest after %d bytes is modified for %d bytes, " + "return value is %d, expected negative.\n", + testname, n, sa, da, m, len, ret); + } + } + } + } + + /* Check some corner cases. */ + src[1] = 'A'; + dest[1] = 'A'; + src[2] = 'B'; + dest[2] = 'B'; + src[3] = 'C'; + dest[3] = 'C'; + src[4] = '\0'; + dest[4] = '\0'; + + src[0] = 0xc1; + dest[0] = 0x41; + ret = strcmp (src, dest); + if (ret <= 0) + print_error ("\nFailed: expected positive, return %d\n", ret); + + src[0] = 0x01; + dest[0] = 0x82; + ret = strcmp (src, dest); + if (ret >= 0) + print_error ("\nFailed: expected negative, return %d\n", ret); + + dest[0] = src[0] = 'D'; + src[3] = 0xc1; + dest[3] = 0x41; + ret = strcmp (src, dest); + if (ret <= 0) + print_error ("\nFailed: expected positive, return %d\n", ret); + + src[3] = 0x01; + dest[3] = 0x82; + ret = strcmp (src, dest); + if (ret >= 0) + print_error ("\nFailed: expected negative, return %d\n", ret); + + //printf ("\n"); + if (errors != 0) + { + printf ("ERROR. FAILED.\n"); + abort (); + } + //exit (0); + printf("ok\n"); +} diff --git a/tests/device/test_libc/test_libc.ino b/tests/device/test_libc/test_libc.ino new file mode 100644 index 0000000000..f4490fa2f9 --- /dev/null +++ b/tests/device/test_libc/test_libc.ino @@ -0,0 +1,59 @@ +#include +#include + +BS_ENV_DECLARE(); + +void setup() +{ + Serial.begin(115200); + BS_RUN(Serial); +} + +extern "C" { + extern void memmove_main(void); + extern void memcpy_main(void); + extern void strcmp_main(void); + extern void tstring_main(void); + extern void libm_test_string(void); + int rand_seed = 1539; +} + +void loop() { +} + +// These tests crash the system if they fail. +TEST_CASE("libc memmove1 test", "[libc]") +{ + Serial.printf("memmove1: "); + memmove_main(); + REQUIRE (1==1); +} + +TEST_CASE("libc memcpy-1 test", "[libc]") +{ + Serial.printf("memcpy-1: "); + memcpy_main(); + REQUIRE(1==1); +} + +TEST_CASE("libc strcmp-1 test", "[libc]") +{ + Serial.printf("strcmp-1: "); + strcmp_main(); + REQUIRE(1==1); +} + +TEST_CASE("libc tstring test", "[libc]") +{ + Serial.printf("tstring: "); + tstring_main(); + REQUIRE(1==1); +} + +TEST_CASE("libc libm string test", "[libc]") +{ + Serial.printf("libm_string: "); + libm_test_string(); + REQUIRE(1==1); +} + diff --git a/tests/device/test_libc/tstring.c b/tests/device/test_libc/tstring.c new file mode 100644 index 0000000000..7e806b1027 --- /dev/null +++ b/tests/device/test_libc/tstring.c @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2002 by Red Hat, Incorporated. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software + * is freely granted, provided that this notice is preserved. + */ + +#include +#include +#include +#include + +#define MAX_1 50 +#define memcmp memcmp_P +#define memcpy memcpy_P +#define memmem memmem_P +#define memchr memchr_P +#define strcat strcat_P +#define strncat strncat_P +#define strcpy strcpy_P +#define strncpy strncpy_P +#define strlen strlen_P +#define strnlen strnlen_P +#define strcmp strcmp_P +#define strncmp strncmp_P + +#define MAX_2 (2 * MAX_1 + MAX_1 / 10) + +void eprintf (int line, char *result, char *expected, int size) +{ + if (size != 0) + printf ("Failure at line %d, result is <%.*s>, should be <%s> of size %d\n", + line, size, result, expected, size); + else + printf ("Failure at line %d, result is <%s>, should be <%s>\n", + line, result, expected); +} + +void mycopy (char *target, char *source, int size) +{ + int i; + + for (i = 0; i < size; ++i) + { + target[i] = source[i]; + } +} + +void myset (char *target, char ch, int size) +{ + int i; + + for (i = 0; i < size; ++i) + { + target[i] = ch; + } +} + +void tstring_main(void) +{ + char target[MAX_1] = "A"; + char first_char; + char second_char; + char array[] = "abcdefghijklmnopqrstuvwxz"; + char array2[] = "0123456789!@#$%^&*("; + char buffer2[MAX_1]; + char buffer3[MAX_1]; + char buffer4[MAX_1]; + char buffer5[MAX_2]; + char buffer6[MAX_2]; + char buffer7[MAX_2]; + char expected[MAX_1]; + char *tmp1, *tmp2, *tmp3, *tmp4, *tmp5, *tmp6, *tmp7; + int i, j, k, x, z, align_test_iterations; + z = 0; + + int test_failed = 0; + + tmp1 = target; + tmp2 = buffer2; + tmp3 = buffer3; + tmp4 = buffer4; + tmp5 = buffer5; + tmp6 = buffer6; + tmp7 = buffer7; + + tmp2[0] = 'Z'; + tmp2[1] = '\0'; + + if (memset (target, 'X', 0) != target || + memcpy (target, "Y", 0) != target || + memmove (target, "K", 0) != target || + strncpy (tmp2, "4", 0) != tmp2 || + strncat (tmp2, "123", 0) != tmp2 || + strcat (target, "") != target) + { + eprintf (__LINE__, target, "A", 0); + test_failed = 1; + } + + if (strcmp (target, "A") || strlen(target) != 1 || memchr (target, 'A', 0) != NULL + || memcmp (target, "J", 0) || strncmp (target, "A", 1) || strncmp (target, "J", 0) || + tmp2[0] != 'Z' || tmp2[1] != '\0') + { + eprintf (__LINE__, target, "A", 0); + test_failed = 1; + } + + tmp2[2] = 'A'; + if (strcpy (target, "") != target || + strncpy (tmp2, "", 4) != tmp2 || + strcat (target, "") != target) + { + eprintf (__LINE__, target, "", 0); + test_failed = 1; + } + + if (target[0] != '\0' || strncmp (target, "", 1) || + memcmp (tmp2, "\0\0\0\0", 4)) + { + eprintf (__LINE__, target, "", 0); + test_failed = 1; + } + + tmp2[2] = 'A'; + if (strncat (tmp2, "1", 3) != tmp2 || + memcmp (tmp2, "1\0A", 3)) + { + eprintf (__LINE__, tmp2, "1\0A", 3); + test_failed = 1; + } + + if (strcpy (tmp3, target) != tmp3 || + strcat (tmp3, "X") != tmp3 || + strncpy (tmp2, "X", 2) != tmp2 || + memset (target, tmp2[0], 1) != target) + { + eprintf (__LINE__, target, "X", 0); + test_failed = 1; + } + + if (strcmp (target, "X") || strlen (target) != 1 || + memchr (target, 'X', 2) != target || + strchr (target, 'X') != target || + memchr (target, 'Y', 2) != NULL || + strchr (target, 'Y') != NULL || + strcmp (tmp3, target) || + strncmp (tmp3, target, 2) || + memcmp (target, "K", 0) || + strncmp (target, tmp3, 3)) + { + eprintf (__LINE__, target, "X", 0); + test_failed = 1; + } + + if (strcpy (tmp3, "Y") != tmp3 || + strcat (tmp3, "Y") != tmp3 || + memset (target, 'Y', 2) != target) + { + eprintf (__LINE__, target, "Y", 0); + test_failed = 1; + } + + target[2] = '\0'; + if (memcmp (target, "YY", 2) || strcmp (target, "YY") || + strlen (target) != 2 || memchr (target, 'Y', 2) != target || + strcmp (tmp3, target) || + strncmp (target, tmp3, 3) || + strncmp (target, tmp3, 4) || + strncmp (target, tmp3, 2) || + strchr (target, 'Y') != target) + { + eprintf (__LINE__, target, "YY", 2); + test_failed = 1; + } + + strcpy (target, "WW"); + if (memcmp (target, "WW", 2) || strcmp (target, "WW") || + strlen (target) != 2 || memchr (target, 'W', 2) != target || + strchr (target, 'W') != target) + { + eprintf (__LINE__, target, "WW", 2); + test_failed = 1; + } + + if (strncpy (target, "XX", 16) != target || + memcmp (target, "XX\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) + { + eprintf (__LINE__, target, "XX\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16); + test_failed = 1; + } + + if (strcpy (tmp3, "ZZ") != tmp3 || + strcat (tmp3, "Z") != tmp3 || + memcpy (tmp4, "Z", 2) != tmp4 || + strcat (tmp4, "ZZ") != tmp4 || + memset (target, 'Z', 3) != target) + { + eprintf (__LINE__, target, "ZZZ", 3); + test_failed = 1; + } + + target[3] = '\0'; + tmp5[0] = '\0'; + strncat (tmp5, "123", 2); + if (memcmp (target, "ZZZ", 3) || strcmp (target, "ZZZ") || + strcmp (tmp3, target) || strcmp (tmp4, target) || + strncmp (target, "ZZZ", 4) || strncmp (target, "ZZY", 3) <= 0 || + strncmp ("ZZY", target, 4) >= 0 || + memcmp (tmp5, "12", 3) || + strlen (target) != 3) + { + eprintf (__LINE__, target, "ZZZ", 3); + test_failed = 1; + } + + target[2] = 'K'; + if (memcmp (target, "ZZZ", 2) || strcmp (target, "ZZZ") >= 0 || + memcmp (target, "ZZZ", 3) >= 0 || strlen (target) != 3 || + memchr (target, 'K', 3) != target + 2 || + strncmp (target, "ZZZ", 2) || strncmp (target, "ZZZ", 4) >= 0 || + strchr (target, 'K') != target + 2) + { + eprintf (__LINE__, target, "ZZK", 3); + test_failed = 1; + } + + strcpy (target, "AAA"); + if (memcmp (target, "AAA", 3) || strcmp (target, "AAA") || + strncmp (target, "AAA", 3) || + strlen (target) != 3) + { + eprintf (__LINE__, target, "AAA", 3); + test_failed = 1; + } + + j = 5; + while (j < MAX_1) + { + for (i = j-1; i <= j+1; ++i) + { + /* don't bother checking unaligned data in the larger + sizes since it will waste time without performing additional testing */ + if ((size_t)i <= 16 * sizeof(long)) + { + align_test_iterations = 2*sizeof(long); + if ((size_t)i <= 2 * sizeof(long) + 1) + z = 2; + else + z = 2 * sizeof(long); + } + else + { + align_test_iterations = 1; + } + + for (x = 0; x < align_test_iterations; ++x) + { + tmp1 = target + x; + tmp2 = buffer2 + x; + tmp3 = buffer3 + x; + tmp4 = buffer4 + x; + tmp5 = buffer5 + x; + tmp6 = buffer6 + x; + + first_char = array[i % (sizeof(array) - 1)]; + second_char = array2[i % (sizeof(array2) - 1)]; + memset (tmp1, first_char, i); + mycopy (tmp2, tmp1, i); + myset (tmp2 + z, second_char, i - z - 1); + if (memcpy (tmp1 + z, tmp2 + z, i - z - 1) != tmp1 + z) + { + printf ("error at line %d\n", __LINE__); + test_failed = 1; + } + + tmp1[i] = '\0'; + tmp2[i] = '\0'; + if (strcpy (expected, tmp2) != expected) + { + printf ("error at line %d\n", __LINE__); + test_failed = 1; + } + tmp2[i-z] = first_char + 1; + if (memmove (tmp2 + z + 1, tmp2 + z, i - z - 1) != tmp2 + z + 1 || + memset (tmp3, first_char, i) != tmp3) + { + printf ("error at line %d\n", __LINE__); + test_failed = 1; + } + + myset (tmp4, first_char, i); + tmp5[0] = '\0'; + if (strncpy (tmp5, tmp1, i+1) != tmp5 || + strcat (tmp5, tmp1) != tmp5) + { + printf ("error at line %d\n", __LINE__); + test_failed = 1; + } + mycopy (tmp6, tmp1, i); + mycopy (tmp6 + i, tmp1, i + 1); + + tmp7[2*i+z] = second_char; + strcpy (tmp7, tmp1); + + (void)strchr (tmp1, second_char); + + if (memcmp (tmp1, expected, i) || strcmp (tmp1, expected) || + strncmp (tmp1, expected, i) || + strncmp (tmp1, expected, i+1) || + strcmp (tmp1, tmp2) >= 0 || memcmp (tmp1, tmp2, i) >= 0 || + strncmp (tmp1, tmp2, i+1) >= 0 || + (int)strlen (tmp1) != i || memchr (tmp1, first_char, i) != tmp1 || + strchr (tmp1, first_char) != tmp1 || + memchr (tmp1, second_char, i) != tmp1 + z || + strchr (tmp1, second_char) != tmp1 + z || + strcmp (tmp5, tmp6) || + strncat (tmp7, tmp1, i+2) != tmp7 || + strcmp (tmp7, tmp6) || + tmp7[2*i+z] != second_char) + { + eprintf (__LINE__, tmp1, expected, 0); + printf ("x is %d\n",x); + printf ("i is %d\n", i); + printf ("tmp1 is <%p>\n", tmp1); + printf ("tmp5 is <%p> <%s>\n", tmp5, tmp5); + printf ("tmp6 is <%p> <%s>\n", tmp6, tmp6); + test_failed = 1; + } + + for (k = 1; k <= align_test_iterations && k <= i; ++k) + { + if (memcmp (tmp3, tmp4, i - k + 1) != 0 || + strncmp (tmp3, tmp4, i - k + 1) != 0) + { + printf ("Failure at line %d, comparing %.*s with %.*s\n", + __LINE__, i, tmp3, i, tmp4); + test_failed = 1; + } + tmp4[i-k] = first_char + 1; + if (memcmp (tmp3, tmp4, i) >= 0 || + strncmp (tmp3, tmp4, i) >= 0 || + memcmp (tmp4, tmp3, i) <= 0 || + strncmp (tmp4, tmp3, i) <= 0) + { + printf ("Failure at line %d, comparing %.*s with %.*s\n", + __LINE__, i, tmp3, i, tmp4); + test_failed = 1; + } + tmp4[i-k] = first_char; + } + } + } + j = ((2 * j) >> 2) << 2; + } + + if (test_failed) + abort(); + + printf("ok\n"); +} diff --git a/tests/host/Makefile b/tests/host/Makefile index c83c55fde3..a65571e737 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -55,7 +55,6 @@ CORE_CPP_FILES := $(addprefix $(CORE_PATH)/,\ Print.cpp \ FS.cpp \ spiffs_api.cpp \ - pgmspace.cpp \ MD5Builder.cpp \ ) @@ -91,7 +90,9 @@ MOCK_C_FILES := $(addprefix common/,\ noniso.c \ ) -INC_PATHS := $(addprefix -I,\ + +INC_PATHS += $(addprefix -I, \ + . \ common \ $(CORE_PATH) \ ) @@ -108,7 +109,7 @@ TEST_CPP_FILES := \ core/test_pgmspace.cpp \ core/test_md5builder.cpp \ core/test_string.cpp \ - core/test_PolledTimeout.cpp + core/test_PolledTimeout.cpp PREINCLUDES := \ -include common/mock.h \ @@ -165,7 +166,7 @@ valgrind: $(OUTPUT_BINARY) $(LCOV) --directory ../../cores/esp8266/ --zerocounters $(VALGRIND) $(VALGRINDFLAGS) $(OUTPUT_BINARY) $(LCOV) --directory $(CORE_PATH) --capture --output-file $(LCOV_DIRECTORY)/app.info - $(GENHTML) $(LCOV_DIRECTORY)/app.info -o $(LCOV_DIRECTORY) + -$(GENHTML) $(LCOV_DIRECTORY)/app.info -o $(LCOV_DIRECTORY) build-info: # show toolchain version @echo "-------- build tools info --------" diff --git a/tests/host/common/Arduino.h b/tests/host/common/Arduino.h index 34b6dc2402..9dc2b041b3 100644 --- a/tests/host/common/Arduino.h +++ b/tests/host/common/Arduino.h @@ -238,7 +238,7 @@ extern "C" { #ifdef __cplusplus -#include "pgmspace.h" +#include #include "WCharacter.h" #include "WString.h" diff --git a/tests/host/sys/pgmspace.h b/tests/host/sys/pgmspace.h new file mode 100644 index 0000000000..baa14b5ea0 --- /dev/null +++ b/tests/host/sys/pgmspace.h @@ -0,0 +1,63 @@ +/* PGMSPACE.H - Accessor utilities/types for accessing PROGMEM data */ + +#ifndef _PGMSPACE_H_ +#define _PGMSPACE_H_ + +// These are no-ops in anything but the ESP8266, where they are defined in +// a custom sys/pgmspace.h header + +#ifndef ICACHE_RODATA_ATTR +#define ICACHE_RODATA_ATTR +#endif + +#ifndef PROGMEM +#define PROGMEM +#endif + +#ifndef PGM_P +#define PGM_P const char * +#endif + +#ifndef PGM_VOID_P +#define PGM_VOID_P const void * +#endif + +#ifndef PSTR +#define PSTR +#endif + +#ifdef __cplusplus + #define pgm_read_byte(addr) (*reinterpret_cast(addr)) + #define pgm_read_word(addr) (*reinterpret_cast(addr)) + #define pgm_read_dword(addr) (*reinterpret_cast(addr)) + #define pgm_read_float(addr) (*reinterpret_cast(addr)) + #define pgm_read_ptr(addr) (*reinterpret_cast(addr)) +#else + #define pgm_read_byte(addr) (*(const uint8_t*)(addr)) + #define pgm_read_word(addr) (*(const uint16_t*)(addr)) + #define pgm_read_dword(addr) (*(const uint32_t*)(addr)) + #define pgm_read_float(addr) (*(const float)(addr)) + #define pgm_read_ptr(addr) (*(const void const *)(addr)) +#endif + +#define pgm_read_byte_near(addr) pgm_read_byte(addr) +#define pgm_read_word_near(addr) pgm_read_word(addr) +#define pgm_read_dword_near(addr) pgm_read_dword(addr) +#define pgm_read_float_near(addr) pgm_read_float(addr) +#define pgm_read_ptr_near(addr) pgm_read_ptr(addr) +#define pgm_read_byte_far(addr) pgm_read_byte(addr) +#define pgm_read_word_far(addr) pgm_read_word(addr) +#define pgm_read_dword_far(addr) pgm_read_dword(addr) +#define pgm_read_float_far(addr) pgm_read_float(addr) +#define pgm_read_ptr_far(addr) pgm_read_ptr(addr) + +// Wrapper inlines for _P functions +#include +#include +inline const char *strstr_P(const char *haystack, const char *needle) { return strstr(haystack, needle); } +inline char *strcpy_P(char *dest, const char *src) { return strcpy(dest, src); } +inline size_t strlen_P(const char *s) { return strlen(s); } +inline int vsnprintf_P(char *str, size_t size, const char *format, va_list ap) { return vsnprintf(str, size, format, ap); } + + +#endif diff --git a/tools/sdk/include/c_types.h b/tools/sdk/include/c_types.h index 05a8d55ef3..40eb5bedf9 100644 --- a/tools/sdk/include/c_types.h +++ b/tools/sdk/include/c_types.h @@ -88,11 +88,9 @@ typedef enum { #define __ICACHE_STRINGIZE(A) __ICACHE_STRINGIZE_NX(A) #define ICACHE_FLASH_ATTR __attribute__((section("\".irom0.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) #define ICACHE_RAM_ATTR __attribute__((section("\".iram.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) -#define ICACHE_RODATA_ATTR __attribute__((section("\".irom.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) #else #define ICACHE_FLASH_ATTR #define ICACHE_RAM_ATTR -#define ICACHE_RODATA_ATTR #endif /* ICACHE_FLASH */ #define STORE_ATTR __attribute__((aligned(4))) diff --git a/tools/sdk/libc/xtensa-lx106-elf/include/assert.h b/tools/sdk/libc/xtensa-lx106-elf/include/assert.h index 83801e34e0..f1c89029aa 100644 --- a/tools/sdk/libc/xtensa-lx106-elf/include/assert.h +++ b/tools/sdk/libc/xtensa-lx106-elf/include/assert.h @@ -7,7 +7,7 @@ extern "C" { #endif #include "_ansi.h" -#include +#include #undef assert diff --git a/tools/sdk/libc/xtensa-lx106-elf/include/ctype.h b/tools/sdk/libc/xtensa-lx106-elf/include/ctype.h index 56ad5abb67..3e1999399d 100644 --- a/tools/sdk/libc/xtensa-lx106-elf/include/ctype.h +++ b/tools/sdk/libc/xtensa-lx106-elf/include/ctype.h @@ -2,6 +2,7 @@ #define _CTYPE_H_ #include "_ansi.h" +#include _BEGIN_STD_C @@ -54,7 +55,11 @@ extern __IMPORT char *__ctype_ptr__; Meanwhile, the real index to __ctype_ptr__+1 must be cast to int, since isalpha(0x100000001LL) must equal isalpha(1), rather than being an out-of-bounds reference on a 64-bit machine. */ -#define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)]) +#ifdef pgm_read_byte + #define __ctype_lookup(__c) pgm_read_byte(&(__ctype_ptr__+sizeof(""[__c]))[(int)(__c)]) +#else + #define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)]) +#endif #define isalpha(__c) (__ctype_lookup(__c)&(_U|_L)) #define isupper(__c) ((__ctype_lookup(__c)&(_U|_L))==_U) diff --git a/tools/sdk/libc/xtensa-lx106-elf/include/locale.h b/tools/sdk/libc/xtensa-lx106-elf/include/locale.h index 2ad63d434d..cbd658e410 100644 --- a/tools/sdk/libc/xtensa-lx106-elf/include/locale.h +++ b/tools/sdk/libc/xtensa-lx106-elf/include/locale.h @@ -1,7 +1,7 @@ /* locale.h Values appropriate for the formatting of monetary and other - numeric quantities. + numberic quantities. */ #ifndef _LOCALE_H_ diff --git a/tools/sdk/libc/xtensa-lx106-elf/include/sys/ctype.h b/tools/sdk/libc/xtensa-lx106-elf/include/sys/ctype.h new file mode 100644 index 0000000000..8527d73561 --- /dev/null +++ b/tools/sdk/libc/xtensa-lx106-elf/include/sys/ctype.h @@ -0,0 +1,9 @@ +/* sys/ctype.h - PROGMEM ctype handlers */ + +#ifndef _SYS_CTYPE_H_ +#define _SYS_CTYPE_H_ + +// Will cause pgm_read_byte to be defined and be used by ctype macros +#include + +#endif diff --git a/tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h b/tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h new file mode 100644 index 0000000000..bb517366bd --- /dev/null +++ b/tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h @@ -0,0 +1,114 @@ +/* PGMSPACE.H - Accessor utilities/types for accessing PROGMEM data */ + +#ifndef _PGMSPACE_H_ +#define _PGMSPACE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ICACHE_RODATA_ATTR + #define ICACHE_RODATA_ATTR __attribute__((section(".irom.text"))) +#endif +#ifndef PROGMEM + // The following two macros cause a parameter to be enclosed in quotes + // by the preopressor (i.e. for concatenating ints to strings) + #define __STRINGIZE_NX(A) #A + #define __STRINGIZE(A) __STRINGIZE_NX(A) + // Since __section__ is supposed to be only use for global variables, + // there could be conflicts when a static/inlined function has them in the + // same file as a non-static PROGMEM object. + // Ref: https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html + // Place each progmem object into its own named section, avoiding conflicts + #define PROGMEM __attribute__((section( "\".irom.text." __FILE__ "." __STRINGIZE(__LINE__) "." __STRINGIZE(__COUNTER__) "\""))) +#endif +#ifndef PGM_P + #define PGM_P const char * +#endif +#ifndef PGM_VOID_P + #define PGM_VOID_P const void * +#endif + +// PSTR() macro modified to start on a 32-bit boundary. This adds on average +// 1.5 bytes/string, but in return memcpy_P and strcpy_P will work 4~8x faster +#ifndef PSTR + #define PSTR(s) (__extension__({static const char __c[] __attribute__((__aligned__(4))) PROGMEM = (s); &__c[0];})) +#endif + +// Flash memory must be read using 32 bit aligned addresses else a processor +// exception will be triggered. +// The order within the 32 bit values are: +// -------------- +// b3, b2, b1, b0 +// w1, w0 + +#define pgm_read_with_offset(addr, res) \ + asm("extui %0, %1, 0, 2\n" /* Extract offset within word (in bytes) */ \ + "sub %1, %1, %0\n" /* Subtract offset from addr, yielding an aligned address */ \ + "l32i.n %1, %1, 0x0\n" /* Load word from aligned address */ \ + "slli %0, %0, 3\n" /* Mulitiply offset by 8, yielding an offset in bits */ \ + "ssr %0\n" /* Prepare to shift by offset (in bits) */ \ + "srl %0, %1\n" /* Shift right; now the requested byte is the first one */ \ + :"=r"(res), "=r"(addr) \ + :"1"(addr) \ + :); + +static inline uint8_t pgm_read_byte_inlined(const void* addr) { + register uint32_t res; + pgm_read_with_offset(addr, res); + return (uint8_t) res; /* This masks the lower byte from the returned word */ +} + +/* Although this says "word", it's actually 16 bit, i.e. half word on Xtensa */ +static inline uint16_t pgm_read_word_inlined(const void* addr) { + register uint32_t res; + pgm_read_with_offset(addr, res); + return (uint16_t) res; /* This masks the lower half-word from the returned word */ +} + +#define pgm_read_byte(addr) pgm_read_byte_inlined(addr) +#define pgm_read_word(addr) pgm_read_word_inlined(addr) +#ifdef __cplusplus + #define pgm_read_dword(addr) (*reinterpret_cast + #define pgm_read_float(addr) (*reinterpret_cast + #define pgm_read_ptr(addr) (*reinterpret_cast +#else + #define pgm_read_dword(addr) (*(const uint32_t*)(addr)) + #define pgm_read_float(addr) (*(const float)(addr)) + #define pgm_read_ptr(addr) (*(const void const *)(addr)) +#endif + +#define pgm_read_byte_near(addr) pgm_read_byte(addr) +#define pgm_read_word_near(addr) pgm_read_word(addr) +#define pgm_read_dword_near(addr) pgm_read_dword(addr) +#define pgm_read_float_near(addr) pgm_read_float(addr) +#define pgm_read_ptr_near(addr) pgm_read_ptr(addr) +#define pgm_read_byte_far(addr) pgm_read_byte(addr) +#define pgm_read_word_far(addr) pgm_read_word(addr) +#define pgm_read_dword_far(addr) pgm_read_dword(addr) +#define pgm_read_float_far(addr) pgm_read_float(addr) +#define pgm_read_ptr_far(addr) pgm_read_ptr(addr) + +#define _SFR_BYTE(n) (n) + +#ifdef __PROG_TYPES_COMPAT__ + +typedef void prog_void; +typedef char prog_char; +typedef unsigned char prog_uchar; +typedef int8_t prog_int8_t; +typedef uint8_t prog_uint8_t; +typedef int16_t prog_int16_t; +typedef uint16_t prog_uint16_t; +typedef int32_t prog_int32_t; +typedef uint32_t prog_uint32_t; + +#endif // defined(__PROG_TYPES_COMPAT__) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/sdk/libc/xtensa-lx106-elf/include/sys/stdio.h b/tools/sdk/libc/xtensa-lx106-elf/include/sys/stdio.h index 0918fe157d..cafc3e25fb 100644 --- a/tools/sdk/libc/xtensa-lx106-elf/include/sys/stdio.h +++ b/tools/sdk/libc/xtensa-lx106-elf/include/sys/stdio.h @@ -1,3 +1,11 @@ +/* sys/stdio.h - #defines for legacy PROGMEM _P functions (no longer needed) */ + +#ifndef _SYS_STDIO_H_ +#define _SYS_STDIO_H_ + +#include +#include + #ifndef _NEWLIB_STDIO_H #define _NEWLIB_STDIO_H @@ -25,3 +33,18 @@ #endif #endif /* _NEWLIB_STDIO_H */ + +#ifdef __cplusplus +extern "C" { +#endif + +int printf_P(PGM_P formatP, ...) __attribute__((format(printf, 1, 2))); +int sprintf_P(char *str, PGM_P formatP, ...) __attribute__((format(printf, 2, 3))); +int snprintf_P(char *str, size_t strSize, PGM_P formatP, ...) __attribute__((format(printf, 3, 4))); +int vsnprintf_P(char *str, size_t strSize, PGM_P formatP, va_list ap) __attribute__((format(printf, 3, 0))); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/sdk/libc/xtensa-lx106-elf/include/sys/string.h b/tools/sdk/libc/xtensa-lx106-elf/include/sys/string.h index ceedf4be10..159b2d8027 100644 --- a/tools/sdk/libc/xtensa-lx106-elf/include/sys/string.h +++ b/tools/sdk/libc/xtensa-lx106-elf/include/sys/string.h @@ -1,2 +1,53 @@ -/* This is a dummy used as a placeholder for - systems that need to have a special header file. */ +/* + * sys/string.h + * + * Xtensa custom PROGMEM string function definitions + */ + +#ifndef _SYS_STRING_H_ +#define _SYS_STRING_H_ + +#include "_ansi.h" +#include +#include +#include + +#define __need_size_t +#define __need_NULL +#include + +#define SIZE_IRRELEVANT 0x7fffffff + +#ifdef __cplusplus +extern "C" { +#endif + +int _EXFUN(memcmp_P,(const _PTR, const _PTR, size_t)); +_PTR _EXFUN(memmem_P, (const _PTR, size_t, const _PTR, size_t)); +_PTR _EXFUN(memcpy_P,(_PTR __restrict, const _PTR __restrict, size_t)); +_PTR _EXFUN(memccpy_P,(_PTR __restrict, const _PTR __restrict, int, size_t)); +_PTR _EXFUN(memchr_P,(const _PTR, int, size_t)); + +char *_EXFUN(strncpy_P,(char *__restrict, const char *__restrict, size_t)); +#define strcpy_P(dest, src) strncpy_P((dest), (src), SIZE_IRRELEVANT) + +char *_EXFUN(strncat_P,(char *__restrict, const char *__restrict, size_t)); +#define strcat_P(dest, src) strncat_P((dest), (src), SIZE_IRRELEVANT) + +int _EXFUN(strncmp_P,(const char *, const char *, size_t)); +#define strcmp_P(str1, str2P) strncmp_P((str1), (str2P), SIZE_IRRELEVANT) + +int _EXFUN(strncasecmp_P,(const char *, const char *, size_t)); +#define strcasecmp_P(str1, str2P) strncasecmp_P((str1), (str2P), SIZE_IRRELEVANT) + +size_t _EXFUN(strnlen_P,(const char *, size_t)); +#define strlen_P(strP) strnlen_P((strP), SIZE_IRRELEVANT) + +char *_EXFUN(strstr_P,(const char *, const char *)); + +#ifdef __cplusplus +} +#endif + + +#endif /* _SYS_STRING_H_ */ diff --git a/tools/sdk/libc/xtensa-lx106-elf/lib/crt0.o b/tools/sdk/libc/xtensa-lx106-elf/lib/crt0.o index 5c2def8ef5..eb555b484d 100644 Binary files a/tools/sdk/libc/xtensa-lx106-elf/lib/crt0.o and b/tools/sdk/libc/xtensa-lx106-elf/lib/crt0.o differ diff --git a/tools/sdk/libc/xtensa-lx106-elf/lib/libc.a b/tools/sdk/libc/xtensa-lx106-elf/lib/libc.a index d5bd4d5522..38cb29722b 100644 Binary files a/tools/sdk/libc/xtensa-lx106-elf/lib/libc.a and b/tools/sdk/libc/xtensa-lx106-elf/lib/libc.a differ diff --git a/tools/sdk/libc/xtensa-lx106-elf/lib/libg.a b/tools/sdk/libc/xtensa-lx106-elf/lib/libg.a index d5bd4d5522..38cb29722b 100644 Binary files a/tools/sdk/libc/xtensa-lx106-elf/lib/libg.a and b/tools/sdk/libc/xtensa-lx106-elf/lib/libg.a differ diff --git a/tools/sdk/libc/xtensa-lx106-elf/lib/libm.a b/tools/sdk/libc/xtensa-lx106-elf/lib/libm.a index 5fa97ece66..881860e3a7 100644 Binary files a/tools/sdk/libc/xtensa-lx106-elf/lib/libm.a and b/tools/sdk/libc/xtensa-lx106-elf/lib/libm.a differ