diff --git a/CSV_Parser.cpp b/CSV_Parser.cpp index bcf1b29..23c801d 100644 --- a/CSV_Parser.cpp +++ b/CSV_Parser.cpp @@ -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(); @@ -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); diff --git a/CSV_Parser.h b/CSV_Parser.h index 88bc52f..d0a03fd 100644 --- a/CSV_Parser.h +++ b/CSV_Parser.h @@ -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 + 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. diff --git a/README.md b/README.md index cd3189a..f2c1447 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/library.properties b/library.properties index 47ea6a8..1d56b3e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=CSV Parser -version=0.2.2 +version=1.0.0 author=Michal Borowski maintainer=Michal Borowski sentence=CSV Parser for Arduino. diff --git a/tests/functionality/functionality.ino b/tests/functionality/functionality.ino index 5325ff3..0d828e5 100644 --- a/tests/functionality/functionality.ino +++ b/tests/functionality/functionality.ino @@ -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"; @@ -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"; @@ -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 @@ -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(); } } @@ -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); } @@ -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.