8000 Added fallbacks strlen_P, strncmp_P, strcmp_P and memcpy_P (fixes #1073) · joglosemarduino/ArduinoJson@f00dfd7 · GitHub
[go: up one dir, main page]

Skip to content

Commit f00dfd7

Browse files
committed
Added fallbacks strlen_P, strncmp_P, strcmp_P and memcpy_P (fixes bblanchon#1073)
1 parent dcca421 commit f00dfd7

File tree

6 files changed

+107
-22
lines changed

6 files changed

+107
-22
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
ArduinoJson: change log
22
=======================
33

4+
HEAD
5+
----
6+
7+
* Added fallback implementations of `strlen_P()`, `strncmp_P()`, `strcmp_P()`, and `memcpy_P()` (issue #1073)
8+
49
v6.11.4 (2019-08-12)
510
-------
611

src/ArduinoJson/Deserialization/FlashStringReader.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class UnsafeFlashStringReader {
1515
: _ptr(reinterpret_cast<const char*>(ptr)) {}
1616

1717
int read() {
18-
8000 return pgm_read_byte_near(_ptr++);
18+
return pgm_read_byte(_ptr++);
1919
}
2020
};
2121

@@ -29,7 +29,7 @@ class SafeFlashStringReader {
2929

3030
int read() {
3131
if (_ptr < _end)
32-
return pgm_read_byte_near(_ptr++);
32+
return pgm_read_byte(_ptr++);
3333
else
3434
return -1;
3535
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// ArduinoJson - arduinojson.org
2+
// Copyright Benoit Blanchon 2014-2019
3+
// MIT License
4+
5+
#pragma once
6+
7+
namespace ARDUINOJSON_NAMESPACE {
8+
// Wraps a const char* so that the our functions are picked only if the
9+
// originals are missing
10+
struct pgm_p {
11+
pgm_p(const char* p) : address(p) {}
12+
const char* address;
13+
};
14+
} // namespace ARDUINOJSON_NAMESPACE
15+
16+
#ifndef strlen_P
17+
inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) {
18+
const char* p = s.address;
19+
while (pgm_read_byte(p)) p++;
20+
return size_t(p - s.address);
21+
}
22+
#endif
23+
24+
#ifndef strncmp_P
25+
inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) {
26+
const char* s1 = a;
27+
const char* s2 = b.address;
28+
while (n-- > 0) {
29+
char c1 = *s1++;
30+
char c2 = static_cast<char>(pgm_read_byte(s2++));
31+
if (c1 < c2) return -1;
32+
if (c1 > c2) return 1;
33+
if (c1 == 0 /* and c2 as well */) return 0;
34+
}
35+
return 0;
36+
}
37+
#endif
38+
39+
#ifndef strcmp_P
40+
inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) {
41+
const char* s1 = a;
42+
const char* s2 = b.address;
43+
for (;;) {
44+
char c1 = *s1++;
45+
char c2 = static_cast<char>(pgm_read_byte(s2++));
46+
if (c1 < c2) return -1;
47+
if (c1 > c2) return 1;
48+
if (c1 == 0 /* and c2 as well */) return 0;
49+
}
50+
}
51+
#endif
52+
53+
#ifndef memcpy_P
54+
inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) {
55+
uint8_t* d = reinterpret_cast<uint8_t*>(dst);
56+
const char* s = src.address;
57+
while (n-- > 0) {
58+
*d++ = pgm_read_byte(s++);
59+
}
60+
return dst;
61+
}
62+
#endif

src/ArduinoJson/Strings/FlashStringAdapter.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#pragma once
66

7+
#include "../Polyfills/pgmspace.hpp"
8+
79
namespace ARDUINOJSON_NAMESPACE {
810

911
class FlashStringAdapter {

test/MixedConfiguration/enable_progmem_1.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,37 @@ TEST_CASE("Flash strings") {
5151
REQUIRE(doc[0] == F("world"));
5252
}
5353
}
54+
55+
TEST_CASE("strlen_P") {
56+
CHECK(strlen_P(FC("")) == 0);
57+
CHECK(strlen_P(FC("a")) == 1);
58+
CHECK(strlen_P(FC("ac")) == 2);
59+
}
60+
61+
TEST_CASE("strncmp_P") {
62+
CHECK(strncmp_P("a", FC("b"), 0) == 0);
63+
CHECK(strncmp_P("a", FC("b"), 1) == -1);
64+
CHECK(strncmp_P("b", FC("a"), 1) == 1);
65+
CHECK(strncmp_P("a", FC("a"), 0) == 0);
66+
CHECK(strncmp_P("a", FC("b"), 2) == -1);
67+
CHECK(strncmp_P("b", FC("a"), 2) == 1);
68+
CHECK(strncmp_P("a", FC("a"), 2) == 0);
69+
}
70+
71+
TEST_CASE("strcmp_P") {
72+
CHECK(strcmp_P("a", FC("b")) == -1);
73+
CHECK(strcmp_P("b", FC("a")) == 1);
74+
CHECK(strcmp_P("a", FC("a")) == 0);
75+
CHECK(strcmp_P("aa", FC("ab")) == -1);
76+
CHECK(strcmp_P("ab", FC("aa")) == 1);
77+
CHECK(strcmp_P("aa", FC("aa")) == 0);
78+
}
79+
80+
TEST_CASE("memcpy_P") {
81+
char dst[4];
82+
CHECK(memcpy_P(dst, FC("ABC"), 4) == dst);
83+
CHECK(dst[0] == 'A');
84+
CHECK(dst[1] == 'B');
85+
CHECK(dst[2] == 'C');
86+
CHECK(dst[3] == 0);
87+
}

test/MixedConfiguration/progmem_emulation.hpp

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77

88
class __FlashStringHelper;
99

10-
typedef char prog_char;
11-
typedef void prog_void;
12-
1310
inline const void* convertPtrToFlash(const void* s) {
1411
return reinterpret_cast<const char*>(s) + 42;
1512
}
@@ -19,23 +16,8 @@ inline const void* convertFlashToPtr(const void* s) {
1916
}
2017

2118
#define F(X) reinterpret_cast<const __FlashStringHelper*>(convertPtrToFlash(X))
19+
#define FC(X) reinterpret_cast<const char*>(convertPtrToFlash(X))
2220

23-
inline uint8_t pgm_read_byte_near(const void* p) {
21+
inline uint8_t pgm_read_byte(const void* p) {
2422
return *reinterpret_cast<const uint8_t*>(convertFlashToPtr(p));
2523
}
26-
27-
inline void* memcpy_P(void* a, const prog_void* b, size_t n) {
28-
return memcpy(a, convertFlashToPtr(b), n);
29-
}
30-
31-
inline int strcmp_P(const char* a, const prog_char* b) {
32-
return strcmp(a, reinterpret_cast<const char*>(convertFlashToPtr(b)));
33-
}
34-
35-
inline int strncmp_P(const char* a, const prog_char* b, size_t n) {
36-
return strncmp(a, reinterpret_cast<const char*>(convertFlashToPtr(b)), n);
37-
}
38-
39-
inline size_t strlen_P(const prog_char* s) {
40-
return strlen(reinterpret_cast<const char*>(convertFlashToPtr(s)));
41-
}

0 commit comments

Comments
 (0)
0