Skip to content

Commit 2c35c7c

Browse files
matthijskooijmanmysterywolf
authored andcommitted
Strings without null-termination
When working with the Arduino String class, I've found that I couldn't efficiently combine it with some external libraries that explicitely pass char* and length around, without nul-terminating their strings. This prompted me to modify and expose the concat (const char* cstr, unsigned int length) method, add a new String(const char* cstr, unsigned int length) constructor. While I was going over the string class, I found some other minor improvements, which are included here. This is a port of arduino/Arduino#1936. The commits are identical, except for some improved commit messages and one commit was dropped since that change was already made by someone else in the meantime. I've provided some testcases by updating the string examples: arduino/Arduino#9239 If this is ok to merge, I'll also provide a PR for the reference documentation. cherry-pick from: arduino/ArduinoCore-API#97
1 parent 55dfc9b commit 2c35c7c

File tree

2 files changed

+25
-19
lines changed

2 files changed

+25
-19
lines changed

Diff for: core/WString.cpp

+20-18
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ String::String(const char *cstr)
4545
if (cstr) copy(cstr, strlen(cstr));
4646
}
4747

48+
String::String(const char *cstr, unsigned int length)
49+
{
50+
init();
51+
if (cstr) copy(cstr, length);
52+
}
53+
4854
String::String(const String &value)
4955
{
5056
init();
@@ -178,7 +184,8 @@ String & String::copy(const char *cstr, unsigned int length)
178184
return *this;
179185
}
180186
len = length;
181-
strcpy(buffer, cstr);
187+
memcpy(buffer, cstr, length);
188+
buffer[len] = '\0';
182189
return *this;
183190
}
184191

@@ -260,8 +267,9 @@ unsigned char String::concat(const char *cstr, unsigned int length)
260267
if (!cstr) return 0;
261268
if (length == 0) return 1;
262269
if (!reserve(newlen)) return 0;
263-
strcpy(buffer + len, cstr);
270+
memcpy(buffer + len, cstr, length);
264271
len = newlen;
272+
buffer[len] = '\0';
265273
return 1;
266274
}
267275

@@ -273,59 +281,56 @@ unsigned char String::concat(const char *cstr)
273281

274282
unsigned char String::concat(char c)
275283
{
276-
char buf[2];
277-
buf[0] = c;
278-
buf[1] = 0;
279-
return concat(buf, 1);
284+
return concat(&c, 1);
280285
}
281286

282287
unsigned char String::concat(unsigned char num)
283288
{
284289
char buf[1 + 3 * sizeof(unsigned char)];
285290
itoa(num, buf, 10);
286-
return concat(buf, strlen(buf));
291+
return concat(buf);
287292
}
288293

289294
unsigned char String::concat(int num)
290295
{
291296
char buf[2 + 3 * sizeof(int)];
292297
itoa(num, buf, 10);
293-
return concat(buf, strlen(buf));
298+
return concat(buf);
294299
}
295300

296301
unsigned char String::concat(unsigned int num)
297302
{
298303
char buf[1 + 3 * sizeof(unsigned int)];
299304
utoa(num, buf, 10);
300-
return concat(buf, strlen(buf));
305+
return concat(buf);
301306
}
302307

303308
unsigned char String::concat(long num)
304309
{
305310
char buf[2 + 3 * sizeof(long)];
306311
ltoa(num, buf, 10);
307-
return concat(buf, strlen(buf));
312+
return concat(buf);
308313
}
309314

310315
unsigned char String::concat(unsigned long num)
311316
{
312317
char buf[1 + 3 * sizeof(unsigned long)];
313318
ultoa(num, buf, 10);
314-
return concat(buf, strlen(buf));
319+
return concat(buf);
315320
}
316321

317322
unsigned char String::concat(float num)
318323
{
319324
char buf[20];
320325
char* string = dtostrnf(num, 4, 2, buf, sizeof(buf));
321-
return concat(string, strlen(string));
326+
return concat(string);
322327
}
323328

324329
unsigned char String::concat(double num)
325330
{
326331
char buf[20];
327332
char* string = dtostrnf(num, 4, 2, buf, sizeof(buf));
328-
return concat(string, strlen(string));
333+
return concat(string);
329334
}
330335

331336
unsigned char String::concat(const __FlashStringHelper * str)
@@ -354,7 +359,7 @@ StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)
354359
StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)
355360
{
356361
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
357-
if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate();
362+
if (!cstr || !a.concat(cstr)) a.invalidate();
358363
return a;
359364
}
360365

@@ -615,10 +620,7 @@ String String::substring(unsigned int left, unsigned int right) const
615620
String out;
616621
if (left >= len) return out;
617622
if (right > len) right = len;
618-
char temp = buffer[right]; // save the replaced character
619-
buffer[right] = '\0';
620-
out = buffer + left; // pointer arithmetic
621-
buffer[right] = temp; //restore character
623+
out.copy(buffer + left, right - left);
622624
return out;
623625
}
624626

Diff for: core/WString.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#define String_class_h
3636
#ifdef __cplusplus
3737

38+
#include <stdint.h>
3839
#include <stdlib.h>
3940
#include <string.h>
4041
#include <ctype.h>
@@ -68,6 +69,8 @@ class String
6869
// fails, the string will be marked as invalid (i.e. "if (s)" will
6970
// be false).
7071
String(const char *cstr = "");
72+
String(const char *cstr, unsigned int length);
73+
String(const uint8_t *cstr, unsigned int length) : String((const char*)cstr, length) {}
7174
String(const String &str);
7275
String(const __FlashStringHelper *str);
7376
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
@@ -107,6 +110,8 @@ class String
107110
// concatenation is considered unsuccessful.
108111
unsigned char concat(const String &str);
109112
unsigned char concat(const char *cstr);
113+
unsigned char concat(const char *cstr, unsigned int length);
114+
unsigned char concat(const uint8_t *cstr, unsigned int length) {return concat((const char*)cstr, length);}
110115
unsigned char concat(char c);
111116
unsigned char concat(unsigned char c);
112117
unsigned char concat(int num);
@@ -208,7 +213,6 @@ class String
208213
void init(void);
209214
void invalidate(void);
210215
unsigned char changeBuffer(unsigned int maxStrLen);
211-
unsigned char concat(const char *cstr, unsigned int length);
212216

213217
// copy and move
214218
String & copy(const char *cstr, unsigned int length);

0 commit comments

Comments
 (0)