Skip to content

Commit

Permalink
<< operator supports more types
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
michalmonday committed Apr 13, 2022
1 parent bb32821 commit f8c819e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 11 deletions.
8 changes: 7 additions & 1 deletion CSV_Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ bool CSV_Parser::readSDfile(const char *f_name) {

// read file and supply it to csv parser
while (csv_file.available())
*this << csv_file.read();
*this << (char)csv_file.read();

csv_file.close();

Expand Down Expand Up @@ -442,6 +442,12 @@ CSV_Parser & CSV_Parser::operator << (const char *s) {
return *this;
}

CSV_Parser & CSV_Parser::operator << (String s) {
supplyChunk(s.c_str());
return *this;
/* return *this << s.c_str(); */
}

CSV_Parser & CSV_Parser::operator << (char c) {
char s[2] = {c, 0};
supplyChunk(s);
Expand Down
15 changes: 15 additions & 0 deletions CSV_Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,26 @@ class CSV_Parser {
/** @brief It's the same as supplyChunk(s) but allows to use operator instead of method call, like:
cp << "my_strings,my_ints\n" << "hello,1\n" << "world,2\n"; */
CSV_Parser & operator << (const char *s);

/** @brief Example:
cp << String(5) + "," + String(6) + "\n"; */
CSV_Parser & operator << (String s);

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

/** @brief This handler converts all types (not covered in other "<<" operator handlers) to String. For example it will handle:
cp << 5;
cp << 5.5f;
cp << 5L;
cp << 0b11111111 */
template<typename T>
CSV_Parser & operator << (T t){
supplyChunk(String(t).c_str());
return *this;
};

/** @brief Forces the previously supplied (but not parsed) chunks to be parsed despite not ending with "\n" or "\r\n" or delimiter.
This function should be called after full csv string is supplied with repetitive supplyChunk method calls.
If the csv string ended with "\n" or "\r\n" then endChunks() call is not necessary.
Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,27 @@ for (int i = 0; i < strlen(csv_str); i++) {
} */
```
Since version 1.0.0, we can supply various types:
```cpp
// original csv file = "101,102,103\n"
// how we could supply it:
cp << '1' << 0 << "1";
cp << ",";
cp << String(102) + ",103\n";
```
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).

**Important**
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:
```cpp
File csv_file = SD.open(f_name); // or FFat.open(f_name);
while (csv_file.available()) {
cp << (char)csv_file.read();
}
```
Without `(char)`, the string representation of ascii number would be stored.
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.


## Examples
Examples directory contains examples showing:
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=CSV Parser
version=0.2.2
version=1.0.0
author=Michal Borowski <[email protected]>
maintainer=Michal Borowski <[email protected]>
sentence=CSV Parser for Arduino.
Expand Down
24 changes: 15 additions & 9 deletions tests/functionality/functionality.ino
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ void expected_numeric_values_test(const TestData &td) {


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

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

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

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

// supplying different types
cp << 301 << "," << 302L << "," << '3' << String("03") << "\n";

int16_t * first = (int16_t*)cp[0];
int16_t * second = (int16_t*)cp[1];
int16_t * third = (int16_t*)cp[2];
if (!first || !second || !third) {
Serial.println("One of 'first', 'second', 'third' was not retrieved.");
Serial.println(F("One of 'first', 'second', 'third' was not retrieved."));
}

if (first[0] != 101 ||
first[1] != 201 ||
first[2] != 301 ||
second[0] != 102 ||
second[1] != 202 ||
second[2] != 302 ||
third[0] != 103 ||
third[1] != 203
third[1] != 203 ||
third[2] != 303
){
Serial.println("Chunked supply test FAILED");
Serial.println(F("Chunked supply test FAILED"));
cp.print();
}
}
Expand All @@ -223,7 +229,7 @@ void setup() {
chunked_supply_test();
tests_done++;

Serial.print("Tests done = ");
Serial.print(F("Tests done = "));
Serial.println(tests_done, DEC);
}

Expand All @@ -237,12 +243,12 @@ void loop() {
// handle diagnostic informations given by assertion and abort program execution:
void __assert(const char *__func, const char *__file, int __lineno, const char *__sexp) {
// transmit diagnostic informations through serial link.
Serial.println("\n\n\n[FAIL]");
Serial.println(F("\n\n\n[FAIL]"));
Serial.println(__func);
Serial.println(__file);
Serial.println(__lineno, DEC);
Serial.println(__sexp);
Serial.println("\n");
Serial.println(F("\n"));
Serial.flush();
// abort program execution.

Expand Down

0 comments on commit f8c819e

Please sign in to comment.