forked from bblanchon/ArduinoJson
Added fallbacks strlen_P, strncmp_P, strcmp_P and memcpy_P (fixes #1073)
This commit is contained in:
@ -1,6 +1,11 @@
|
|||||||
ArduinoJson: change log
|
ArduinoJson: change log
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
HEAD
|
||||||
|
----
|
||||||
|
|
||||||
|
* Added fallback implementations of `strlen_P()`, `strncmp_P()`, `strcmp_P()`, and `memcpy_P()` (issue #1073)
|
||||||
|
|
||||||
v6.11.4 (2019-08-12)
|
v6.11.4 (2019-08-12)
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class UnsafeFlashStringReader {
|
|||||||
: _ptr(reinterpret_cast<const char*>(ptr)) {}
|
: _ptr(reinterpret_cast<const char*>(ptr)) {}
|
||||||
|
|
||||||
int read() {
|
int read() {
|
||||||
return pgm_read_byte_near(_ptr++);
|
return pgm_read_byte(_ptr++);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ class SafeFlashStringReader {
|
|||||||
|
|
||||||
int read() {
|
int read() {
|
||||||
if (_ptr < _end)
|
if (_ptr < _end)
|
||||||
return pgm_read_byte_near(_ptr++);
|
return pgm_read_byte(_ptr++);
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
62
src/ArduinoJson/Polyfills/pgmspace.hpp
Normal file
62
src/ArduinoJson/Polyfills/pgmspace.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2019
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
// Wraps a const char* so that the our functions are picked only if the
|
||||||
|
// originals are missing
|
||||||
|
struct pgm_p {
|
||||||
|
pgm_p(const char* p) : address(p) {}
|
||||||
|
const char* address;
|
||||||
|
};
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
|
||||||
|
#ifndef strlen_P
|
||||||
|
inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) {
|
||||||
|
const char* p = s.address;
|
||||||
|
while (pgm_read_byte(p)) p++;
|
||||||
|
return size_t(p - s.address);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef strncmp_P
|
||||||
|
inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) {
|
||||||
|
const char* s1 = a;
|
||||||
|
const char* s2 = b.address;
|
||||||
|
while (n-- > 0) {
|
||||||
|
char c1 = *s1++;
|
||||||
|
char c2 = static_cast<char>(pgm_read_byte(s2++));
|
||||||
|
if (c1 < c2) return -1;
|
||||||
|
if (c1 > c2) return 1;
|
||||||
|
if (c1 == 0 /* and c2 as well */) return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef strcmp_P
|
||||||
|
inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) {
|
||||||
|
const char* s1 = a;
|
||||||
|
const char* s2 = b.address;
|
||||||
|
for (;;) {
|
||||||
|
char c1 = *s1++;
|
||||||
|
char c2 = static_cast<char>(pgm_read_byte(s2++));
|
||||||
|
if (c1 < c2) return -1;
|
||||||
|
if (c1 > c2) return 1;
|
||||||
|
if (c1 == 0 /* and c2 as well */) return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef memcpy_P
|
||||||
|
inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) {
|
||||||
|
uint8_t* d = reinterpret_cast<uint8_t*>(dst);
|
||||||
|
const char* s = src.address;
|
||||||
|
while (n-- > 0) {
|
||||||
|
*d++ = pgm_read_byte(s++);
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
#endif
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Polyfills/pgmspace.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
class FlashStringAdapter {
|
class FlashStringAdapter {
|
||||||
|
@ -51,3 +51,37 @@ TEST_CASE("Flash strings") {
|
|||||||
REQUIRE(doc[0] == F("world"));
|
REQUIRE(doc[0] == F("world"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("strlen_P") {
|
||||||
|
CHECK(strlen_P(FC("")) == 0);
|
||||||
|
CHECK(strlen_P(FC("a")) == 1);
|
||||||
|
CHECK(strlen_P(FC("ac")) == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("strncmp_P") {
|
||||||
|
CHECK(strncmp_P("a", FC("b"), 0) == 0);
|
||||||
|
CHECK(strncmp_P("a", FC("b"), 1) == -1);
|
||||||
|
CHECK(strncmp_P("b", FC("a"), 1) == 1);
|
||||||
|
CHECK(strncmp_P("a", FC("a"), 0) == 0);
|
||||||
|
CHECK(strncmp_P("a", FC("b"), 2) == -1);
|
||||||
|
CHECK(strncmp_P("b", FC("a"), 2) == 1);
|
||||||
|
CHECK(strncmp_P("a", FC("a"), 2) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("strcmp_P") {
|
||||||
|
CHECK(strcmp_P("a", FC("b")) == -1);
|
||||||
|
CHECK(strcmp_P("b", FC("a")) == 1);
|
||||||
|
CHECK(strcmp_P("a", FC("a")) == 0);
|
||||||
|
CHECK(strcmp_P("aa", FC("ab")) == -1);
|
||||||
|
CHECK(strcmp_P("ab", FC("aa")) == 1);
|
||||||
|
CHECK(strcmp_P("aa", FC("aa")) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("memcpy_P") {
|
||||||
|
char dst[4];
|
||||||
|
CHECK(memcpy_P(dst, FC("ABC"), 4) == dst);
|
||||||
|
CHECK(dst[0] == 'A');
|
||||||
|
CHECK(dst[1] == 'B');
|
||||||
|
CHECK(dst[2] == 'C');
|
||||||
|
CHECK(dst[3] == 0);
|
||||||
|
}
|
||||||
|
@ -7,9 +7,6 @@
|
|||||||
|
|
||||||
class __FlashStringHelper;
|
class __FlashStringHelper;
|
||||||
|
|
||||||
typedef char prog_char;
|
|
||||||
typedef void prog_void;
|
|
||||||
|
|
||||||
inline const void* convertPtrToFlash(const void* s) {
|
inline const void* convertPtrToFlash(const void* s) {
|
||||||
return reinterpret_cast<const char*>(s) + 42;
|
return reinterpret_cast<const char*>(s) + 42;
|
||||||
}
|
}
|
||||||
@ -19,23 +16,8 @@ inline const void* convertFlashToPtr(const void* s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define F(X) reinterpret_cast<const __FlashStringHelper*>(convertPtrToFlash(X))
|
#define F(X) reinterpret_cast<const __FlashStringHelper*>(convertPtrToFlash(X))
|
||||||
|
#define FC(X) reinterpret_cast<const char*>(convertPtrToFlash(X))
|
||||||
|
|
||||||
inline uint8_t pgm_read_byte_near(const void* p) {
|
inline uint8_t pgm_read_byte(const void* p) {
|
||||||
return *reinterpret_cast<const uint8_t*>(convertFlashToPtr(p));
|
return *reinterpret_cast<const uint8_t*>(convertFlashToPtr(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void* memcpy_P(void* a, const prog_void* b, size_t n) {
|
|
||||||
return memcpy(a, convertFlashToPtr(b), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int strcmp_P(const char* a, const prog_char* b) {
|
|
||||||
return strcmp(a, reinterpret_cast<const char*>(convertFlashToPtr(b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int strncmp_P(const char* a, const prog_char* b, size_t n) {
|
|
||||||
return strncmp(a, reinterpret_cast<const char*>(convertFlashToPtr(b)), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t strlen_P(const prog_char* s) {
|
|
||||||
return strlen(reinterpret_cast<const char*>(convertFlashToPtr(s)));
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user