Skip to content

Commit f8c819e

Browse files
committed
<< operator supports more types
As mentioned in README.md, file.read() return must be cast to char like: ```cpp File csv_file = SD.open(f_name); // or FFat.open(f_name); while (csv_file.available()) { cp << (char)csv_file.read(); } ``` Otherwise issues may occur.
1 parent bb32821 commit f8c819e

File tree

5 files changed

+59
-11
lines changed

5 files changed

+59
-11
lines changed

CSV_Parser.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ bool CSV_Parser::readSDfile(const char *f_name) {
120120

121121
// read file and supply it to csv parser
122122
while (csv_file.available())
123-
*this << csv_file.read();
123+
*this << (char)csv_file.read();
124124

125125
csv_file.close();
126126

@@ -442,6 +442,12 @@ CSV_Parser & CSV_Parser::operator << (const char *s) {
442442
return *this;
443443
}
444444

445+
CSV_Parser & CSV_Parser::operator << (String s) {
446+
supplyChunk(s.c_str());
447+
return *this;
448+
/* return *this << s.c_str(); */
449+
}
450+
445451
CSV_Parser & CSV_Parser::operator << (char c) {
446452
char s[2] = {c, 0};
447453
supplyChunk(s);

CSV_Parser.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,26 @@ class CSV_Parser {
161161
/** @brief It's the same as supplyChunk(s) but allows to use operator instead of method call, like:
162162
cp << "my_strings,my_ints\n" << "hello,1\n" << "world,2\n"; */
163163
CSV_Parser & operator << (const char *s);
164+
165+
/** @brief Example:
166+
cp << String(5) + "," + String(6) + "\n"; */
167+
CSV_Parser & operator << (String s);
164168

165169
/** @brief Example:
166170
cp << 'a' << ',' << 'b'; */
167171
CSV_Parser & operator << (char c);
168172

173+
/** @brief This handler converts all types (not covered in other "<<" operator handlers) to String. For example it will handle:
174+
cp << 5;
175+
cp << 5.5f;
176+
cp << 5L;
177+
cp << 0b11111111 */
178+
template<typename T>
179+
CSV_Parser & operator << (T t){
180+
supplyChunk(String(t).c_str());
181+
return *this;
182+
};
183+
169184
/** @brief Forces the previously supplied (but not parsed) chunks to be parsed despite not ending with "\n" or "\r\n" or delimiter.
170185
This function should be called after full csv string is supplied with repetitive supplyChunk method calls.
171186
If the csv string ended with "\n" or "\r\n" then endChunks() call is not necessary.

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,27 @@ for (int i = 0; i < strlen(csv_str); i++) {
139139
} */
140140
```
141141
142+
Since version 1.0.0, we can supply various types:
143+
```cpp
144+
// original csv file = "101,102,103\n"
145+
// how we could supply it:
146+
cp << '1' << 0 << "1";
147+
cp << ",";
148+
cp << String(102) + ",103\n";
149+
```
150+
Floats can be supplied as well. In general, any types can be supplied, the principle is: if the type isn't "String", "char \*" or "char", then the String(supplied_value) will be appended (before being parsed and stored as a type specified in the format string).
151+
152+
**Important**
153+
Arduino built-in File.read() method returns an integer (instead of a char). Therefore, it's important to cast its return before supplying it to CSV_Parser object, like:
154+
```cpp
155+
File csv_file = SD.open(f_name); // or FFat.open(f_name);
156+
while (csv_file.available()) {
157+
cp << (char)csv_file.read();
158+
}
159+
```
160+
Without `(char)`, the string representation of ascii number would be stored.
161+
Before the 1.0.0 version, the `cp << 97;` expression would append letter 'a' (because '97' stands for 'a' in ascii table). From 1.0.0 version onwards, the `cp << 97;` is equivalent to `cp << String(97);`, it will append '97' instead of 'a'. That is correct behaviour in my opinion, however due to design of Arduino built-in "File.read()" method, which returns an integer, it is necessary to cast it's return (with `(char)csv_file.read()` as shown above), and problems may occur if some existing code (using this library) doesn't explicitly cast it.
162+
142163

143164
## Examples
144165
Examples directory contains examples showing:

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=CSV Parser
2-
version=0.2.2
2+
version=1.0.0
33
author=Michal Borowski <[email protected]>
44
maintainer=Michal Borowski <[email protected]>
55
sentence=CSV Parser for Arduino.

tests/functionality/functionality.ino

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ void expected_numeric_values_test(const TestData &td) {
142142

143143

144144
void unsigned_values_test() {
145-
Serial.println("Testing unsigned values");
145+
Serial.println(F("Testing unsigned values"));
146146
static const char * csv_str = "bytes,words,dwords\n"
147147
"255,65535,4294967295\n"
148148
"254,65534,4294967294\n";
@@ -155,7 +155,7 @@ void unsigned_values_test() {
155155
assert(words[0] == 65535 && words[1] == 65534);
156156
assert(dwords[0] == 4294967295L && dwords[1] == 4294967294L);
157157

158-
Serial.println("Testing unsigned values (with signed value between)");
158+
Serial.println(F("Testing unsigned values (with signed value between)"));
159159
static const char * csv_str_2 = "bytes,signed,dwords\n"
160160
"255,1,4294967295\n"
161161
"254,1,4294967294\n";
@@ -170,7 +170,7 @@ void unsigned_values_test() {
170170
}
171171

172172
void chunked_supply_test() {
173-
Serial.println("Chunked supply test");
173+
Serial.println(F("Chunked supply test"));
174174
CSV_Parser cp("ddd", /*has_header*/ false, /*delimiter*/ ',', /*quote_char*/ "'");
175175

176176
// closing double quote and comma is supplied at once
@@ -182,21 +182,27 @@ void chunked_supply_test() {
182182
// opening quote is supplied alone
183183
cp << "201," << "'" << "202',203\n";
184184

185+
// supplying different types
186+
cp << 301 << "," << 302L << "," << '3' << String("03") << "\n";
187+
185188
int16_t * first = (int16_t*)cp[0];
186189
int16_t * second = (int16_t*)cp[1];
187190
int16_t * third = (int16_t*)cp[2];
188191
if (!first || !second || !third) {
189-
Serial.println("One of 'first', 'second', 'third' was not retrieved.");
192+
Serial.println(F("One of 'first', 'second', 'third' was not retrieved."));
190193
}
191194

192195
if (first[0] != 101 ||
193196
first[1] != 201 ||
197+
first[2] != 301 ||
194198
second[0] != 102 ||
195199
second[1] != 202 ||
200+
second[2] != 302 ||
196201
third[0] != 103 ||
197-
third[1] != 203
202+
third[1] != 203 ||
203+
third[2] != 303
198204
){
199-
Serial.println("Chunked supply test FAILED");
205+
Serial.println(F("Chunked supply test FAILED"));
200206
cp.print();
201207
}
202208
}
@@ -223,7 +229,7 @@ void setup() {
223229
chunked_supply_test();
224230
tests_done++;
225231

226-
Serial.print("Tests done = ");
232+
Serial.print(F("Tests done = "));
227233
Serial.println(tests_done, DEC);
228234
}
229235

@@ -237,12 +243,12 @@ void loop() {
237243
// handle diagnostic informations given by assertion and abort program execution:
238244
void __assert(const char *__func, const char *__file, int __lineno, const char *__sexp) {
239245
// transmit diagnostic informations through serial link.
240-
Serial.println("\n\n\n[FAIL]");
246+
Serial.println(F("\n\n\n[FAIL]"));
241247
Serial.println(__func);
242248
Serial.println(__file);
243249
Serial.println(__lineno, DEC);
244250
Serial.println(__sexp);
245-
Serial.println("\n");
251+
Serial.println(F("\n"));
246252
Serial.flush();
247253
// abort program execution.
248254

0 commit comments

Comments
 (0)