diff --git a/CHANGELOG.md b/CHANGELOG.md index c5a0a3e4..709c8769 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- `CppLibrary` can now report `gcc_version` ### Changed +- `arduino_ci_remote.rb` now formats tasks with multiple output lines more nicely +- Templates for CI classes are now pass-by-value (no const reference) ### Deprecated ### Removed ### Fixed +- Replaced pipes with `Open3.capture3` to avoid deadlocks when commands have too much output +- `ci_config.rb` now returns empty arrays (instead of nil) for undefined config keys +- `pgmspace.h` explictly includes `` +- `__FlashStringHelper` should now be properly mocked for compilation +- `WString.h` bool operator now works and is simpler ### Security diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dde6db80..75b4fdbf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,6 +18,7 @@ Be prepared to write tests to accompany any code you would like to see merged. ## Packaging the Gem * Merge pull request with new features +* `git pull --rebase` * Bump the version in lib/arduino_ci/version.rb and change it in README.md (since rubydoc.info doesn't always redirect to the latest version) * Update the sections of `CHANGELOG.md` * `git add README.md CHANGELOG.md lib/arduino_ci/version.rb` diff --git a/cpp/arduino/ArduinoDefines.h b/cpp/arduino/ArduinoDefines.h index 42006268..d10e3de2 100644 --- a/cpp/arduino/ArduinoDefines.h +++ b/cpp/arduino/ArduinoDefines.h @@ -1,5 +1,7 @@ #pragma once +#include + #define HIGH 0x1 #define LOW 0x0 diff --git a/cpp/arduino/PinHistory.h b/cpp/arduino/PinHistory.h index 85c56884..2e9a470c 100644 --- a/cpp/arduino/PinHistory.h +++ b/cpp/arduino/PinHistory.h @@ -86,7 +86,7 @@ class PinHistory : public ObservableDataStream { // this sets the value of the pin authoritatively // so if there was a queue, dump it. // the actual "set" operation doesn't happen until the next read - const T &operator=(const T& i) { + T operator=(const T& i) { qIn.clear(); qOut.push(i); advertiseBit(qOut.back()); // not valid for all possible types but whatever diff --git a/cpp/arduino/Print.h b/cpp/arduino/Print.h index c1dcdde1..d9ab6d09 100644 --- a/cpp/arduino/Print.h +++ b/cpp/arduino/Print.h @@ -32,7 +32,6 @@ class Print virtual size_t write(uint8_t) = 0; size_t write(const char *str) { return str == NULL ? 0 : write((const uint8_t *)str, String(str).length()); } - size_t write(const __FlashStringHelper *str) { return write((const char *)str); } virtual size_t write(const uint8_t *buffer, size_t size) { size_t n; @@ -41,28 +40,30 @@ class Print } size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } - size_t print(const String &s) { return write(s.c_str(), s.length()); } - size_t print(const char* str) { return print(String(str)); } - size_t print(char c) { return print(String(c)); } - size_t print(unsigned char b, int base) { return print(String(b, base)); } - size_t print(int n, int base) { return print(String(n, base)); } - size_t print(unsigned int n, int base) { return print(String(n, base)); } - size_t print(long n, int base) { return print(String(n, base)); } - size_t print(unsigned long n, int base) { return print(String(n, base)); } - size_t print(double n, int digits) { return print(String(n, digits)); } - size_t print(const Printable& x) { return x.printTo(*this); } + size_t print(const String &s) { return write(s.c_str(), s.length()); } + size_t print(const __FlashStringHelper *str) { return print(reinterpret_cast(str)); } + size_t print(const char* str) { return print(String(str)); } + size_t print(char c) { return print(String(c)); } + size_t print(unsigned char b, int base) { return print(String(b, base)); } + size_t print(int n, int base) { return print(String(n, base)); } + size_t print(unsigned int n, int base) { return print(String(n, base)); } + size_t print(long n, int base) { return print(String(n, base)); } + size_t print(unsigned long n, int base) { return print(String(n, base)); } + size_t print(double n, int digits) { return print(String(n, digits)); } + size_t print(const Printable& x) { return x.printTo(*this); } - size_t println(void) { return print("\r\n"); } - size_t println(const String &s) { return print(s) + println(); } - size_t println(const char* c) { return println(String(c)); } - size_t println(char c) { return println(String(c)); } - size_t println(unsigned char b, int base) { return println(String(b, base)); } - size_t println(int num, int base) { return println(String(num, base)); } - size_t println(unsigned int num, int base) { return println(String(num, base)); } - size_t println(long num, int base) { return println(String(num, base)); } - size_t println(unsigned long num, int base) { return println(String(num, base)); } - size_t println(double num, int digits) { return println(String(num, digits)); } - size_t println(const Printable& x) { return print(x) + println(); } + size_t println(void) { return print("\r\n"); } + size_t println(const String &s) { return print(s) + println(); } + size_t println(const __FlashStringHelper *str) { return println(reinterpret_cast(str)); } + size_t println(const char* c) { return println(String(c)); } + size_t println(char c) { return println(String(c)); } + size_t println(unsigned char b, int base) { return println(String(b, base)); } + size_t println(int num, int base) { return println(String(num, base)); } + size_t println(unsigned int num, int base) { return println(String(num, base)); } + size_t println(long num, int base) { return println(String(num, base)); } + size_t println(unsigned long num, int base) { return println(String(num, base)); } + size_t println(double num, int digits) { return println(String(num, digits)); } + size_t println(const Printable& x) { return print(x) + println(); } virtual void flush() { } diff --git a/cpp/arduino/SoftwareSerial.h b/cpp/arduino/SoftwareSerial.h index f2d567b0..6f8870fd 100644 --- a/cpp/arduino/SoftwareSerial.h +++ b/cpp/arduino/SoftwareSerial.h @@ -10,16 +10,19 @@ class SoftwareSerial : public Stream private: int mPinIn; int mPinOut; - bool mInverse; bool mIsListening; GodmodeState* mState; unsigned long mOffset; // bits to offset stream bool bigEndian; public: - SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false) { + // @TODO this is public for now to avoid a compiler warning + bool mInvertLogic; // @TODO not sure how to implement yet + + SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool invertLogic = false) { mPinIn = receivePin; mPinOut = transmitPin; + mIsListening = invertLogic; mIsListening = false; mOffset = 0; // godmode starts with 1 bit in the queue mState = GODMODE(); diff --git a/cpp/arduino/WString.h b/cpp/arduino/WString.h index 8e362a30..e92cf919 100644 --- a/cpp/arduino/WString.h +++ b/cpp/arduino/WString.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include #include "AvrMath.h" @@ -9,24 +9,16 @@ typedef std::string string; -//typedef const char __FlashStringHelper; class __FlashStringHelper; #define F(string_literal) (reinterpret_cast(PSTR(string_literal))) // Compatibility with string class class String: public string { - public: - - // allow "string s; if (s) {}" - // http://www.artima.com/cppsource/safebool.html - typedef void (String::*TTDNSCstring)() const; - void ttdnsc() const {} - operator TTDNSCstring() const { return &String::ttdnsc; } - private: - static const char* digit(int val) { - static const char* bank = "0123456789ABCDEF"; + static const char *digit(int val) + { + static const char *bank = "0123456789ABCDEF"; return bank + val; } @@ -44,122 +36,126 @@ class String: public string static string dtoas(double val, int decimalPlaces) { double r = 0.5 * pow(0.1, decimalPlaces); // make sure that integer truncation will properly round - if (::isnan(val)) return "nan"; - if (::isinf(val)) return "inf"; + if (std::isnan(val)) return "nan"; + if (std::isinf(val)) return "inf"; val += val > 0 ? r : -r; if (val > 4294967040.0) return "ovf"; if (val <-4294967040.0) return "ovf"; return mytoas(val, 10) + "." + mytoa(abs(val - (long)val) * pow(10, decimalPlaces), 10); } -public: - ~String(void) {} - String(const __FlashStringHelper *str): string((const char *)str) {} - String(const char *cstr = ""): string(cstr) {} - String(const string &str): string(str) {} - String(const String &str): string(str) {} - explicit String(char c): string(1, c) {} - - explicit String(unsigned char val, unsigned char base=10): string(mytoa(val, base)) {} - explicit String(int val, unsigned char base=10): string(mytoas(val, base)) {} - explicit String(unsigned int val , unsigned char base=10): string(mytoa(val, base)) {} - explicit String(long val, unsigned char base=10): string(mytoas(val, base)) {} - explicit String(unsigned long val, unsigned char base=10): string(mytoa(val, base)) {} - - explicit String(float val, unsigned char decimalPlaces=2): string(dtoas(val, decimalPlaces)) {} - explicit String(double val, unsigned char decimalPlaces=2): string(dtoas(val, decimalPlaces)) {} - - String & operator = (const String &rhs) { assign(rhs); return *this; } - String & operator = (const string &rhs) { assign(rhs); return *this; } - String & operator = (const char *cstr) { assign(cstr); return *this; } - String & operator = (const char c) { assign(1, c); return *this; } - - unsigned char concat(const __FlashStringHelper *str) { append((const char *)str); return 1; } - unsigned char concat(const String &str) { append(str); return 1; } - unsigned char concat(const char *cstr) { append(cstr); return 1; } - unsigned char concat(char c) { append(1, c); return 1; } - unsigned char concat(unsigned char c) { append(1, c); return 1; } - unsigned char concat(int num) { append(String(num)); return 1; } - unsigned char concat(unsigned int num) { append(String(num)); return 1; } - unsigned char concat(long num) { append(String(num)); return 1; } - unsigned char concat(unsigned long num) { append(String(num)); return 1; } - unsigned char concat(float num) { append(String(num)); return 1; } - unsigned char concat(double num) { append(String(num)); return 1; } - - String & operator += (const __FlashStringHelper *rhs) { concat(rhs); return *this; } - String & operator += (const String &rhs) { concat(rhs); return *this; } - String & operator += (const char *cstr) { concat(cstr); return *this; } - String & operator += (char c) { concat(c); return *this; } - String & operator += (unsigned char num) { concat(num); return *this; } - String & operator += (int num) { concat(num); return *this; } - String & operator += (unsigned int num) { concat(num); return *this; } - String & operator += (long num) { concat(num); return *this; } - String & operator += (unsigned long num) { concat(num); return *this; } - String & operator += (float num) { concat(num); return *this; } - String & operator += (double num) { concat(num); return *this; } - - - int compareTo(const String &s) const { return compare(s); } - unsigned char equals(const String &s) const { return compareTo(s) == 0; } - unsigned char equals(const char *cstr) const { return compareTo(String(cstr)) == 0; } - unsigned char equal(const String &s) const { return equals(s); } - unsigned char equal(const char *cstr) const { return equals(cstr); } - unsigned char equalsIgnoreCase(const String &s) const { - String a = String(*this); - String b = String(s); - a.toUpperCase(); - b.toUpperCase(); - return a.compare(b) == 0; - } - - unsigned char startsWith(const String &prefix) const { return find(prefix) == 0; } - unsigned char startsWith(const String &prefix, unsigned int offset) const { return find(prefix, offset) == offset; } - unsigned char endsWith(const String &suffix) const { return rfind(suffix) == length() - suffix.length(); } - - char charAt(unsigned int index) const { return operator[](index); } - void setCharAt(unsigned int index, char c) { (*this)[index] = c; } - - void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const { copy((char*)buf, bufsize, index); } - void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const - { getBytes((unsigned char *)buf, bufsize, index); } - - int indexOf( char ch ) const { return find(ch); } - int indexOf( char ch, unsigned int fromIndex ) const { return find(ch, fromIndex); } - int indexOf( const String &str ) const { return find(str); } - int indexOf( const String &str, unsigned int fromIndex ) const { return find(str, fromIndex); } - int lastIndexOf( char ch ) const { return rfind(ch); } - int lastIndexOf( char ch, unsigned int fromIndex ) const { return rfind(ch, fromIndex); } - int lastIndexOf( const String &str ) const { return rfind(str); } - int lastIndexOf( const String &str, unsigned int fromIndex ) const { return rfind(str, fromIndex); } - String substring( unsigned int beginIndex ) const { return String(substr(beginIndex)); } - String substring( unsigned int beginIndex, unsigned int endIndex ) const { return String(substr(beginIndex, endIndex)); } - - void replace(const String& target, const String& repl) { - int i = 0; - while ((i = find(target, i)) != npos) { - assign(substr(0, i) + repl + substr(i + target.length())); - i += repl.length(); + public: + ~String(void) {} + String(const __FlashStringHelper *str): string((const char *)str) {} + String(const char *cstr = ""): string(cstr) {} + String(const string &str): string(str) {} + String(const String &str): string(str) {} + explicit String(char c): string(1, c) {} + + explicit String(unsigned char val, unsigned char base=10): string(mytoa(val, base)) {} + explicit String(int val, unsigned char base=10): string(mytoas(val, base)) {} + explicit String(unsigned int val , unsigned char base=10): string(mytoa(val, base)) {} + explicit String(long val, unsigned char base=10): string(mytoas(val, base)) {} + explicit String(unsigned long val, unsigned char base=10): string(mytoa(val, base)) {} + + explicit String(float val, unsigned char decimalPlaces=2): string(dtoas(val, decimalPlaces)) {} + explicit String(double val, unsigned char decimalPlaces=2): string(dtoas(val, decimalPlaces)) {} + + operator bool() const { + return true; + } + + String & operator = (const String &rhs) { assign(rhs); return *this; } + String & operator = (const string &rhs) { assign(rhs); return *this; } + String & operator = (const char *cstr) { assign(cstr); return *this; } + String & operator = (const char c) { assign(1, c); return *this; } + + unsigned char concat(const __FlashStringHelper *str) { append((const char *)str); return 1; } + unsigned char concat(const String &str) { append(str); return 1; } + unsigned char concat(const char *cstr) { append(cstr); return 1; } + unsigned char concat(char c) { append(1, c); return 1; } + unsigned char concat(unsigned char c) { append(1, c); return 1; } + unsigned char concat(int num) { append(String(num)); return 1; } + unsigned char concat(unsigned int num) { append(String(num)); return 1; } + unsigned char concat(long num) { append(String(num)); return 1; } + unsigned char concat(unsigned long num) { append(String(num)); return 1; } + unsigned char concat(float num) { append(String(num)); return 1; } + unsigned char concat(double num) { append(String(num)); return 1; } + + String & operator += (const __FlashStringHelper *rhs) { concat(rhs); return *this; } + String & operator += (const String &rhs) { concat(rhs); return *this; } + String & operator += (const char *cstr) { concat(cstr); return *this; } + String & operator += (char c) { concat(c); return *this; } + String & operator += (unsigned char num) { concat(num); return *this; } + String & operator += (int num) { concat(num); return *this; } + String & operator += (unsigned int num) { concat(num); return *this; } + String & operator += (long num) { concat(num); return *this; } + String & operator += (unsigned long num) { concat(num); return *this; } + String & operator += (float num) { concat(num); return *this; } + String & operator += (double num) { concat(num); return *this; } + + + int compareTo(const String &s) const { return compare(s); } + unsigned char equals(const String &s) const { return compareTo(s) == 0; } + unsigned char equals(const char *cstr) const { return compareTo(String(cstr)) == 0; } + unsigned char equal(const String &s) const { return equals(s); } + unsigned char equal(const char *cstr) const { return equals(cstr); } + unsigned char equalsIgnoreCase(const String &s) const { + String a = String(*this); + String b = String(s); + a.toUpperCase(); + b.toUpperCase(); + return a.compare(b) == 0; } - } - void replace(char target, char repl) { - replace(String(target), String(repl)); - } - void remove(unsigned int index) { assign(substr(0, index)); } - void remove(unsigned int index, unsigned int count) { assign(substr(0, index) + substr(min(length(), index + count), count)); } - void toLowerCase(void) { std::transform(begin(), end(), begin(), ::tolower); } - void toUpperCase(void) { std::transform(begin(), end(), begin(), ::toupper); } - - void trim(void) { - int b; - int e; - for (b = 0; b < length() && isSpace(charAt(b)); ++b); - for (e = length() - 1; e > b && isSpace(charAt(e)); --e); - assign(substr(b, e - b + 1)); - } - - long toInt(void) const { return std::stol(*this); } - float toFloat(void) const { return std::stof(*this); } - double toDouble(void) const { return std::stod(*this); } + + unsigned char startsWith(const String &prefix) const { return find(prefix) == 0; } + unsigned char startsWith(const String &prefix, unsigned int offset) const { return find(prefix, offset) == offset; } + unsigned char endsWith(const String &suffix) const { return rfind(suffix) == length() - suffix.length(); } + + char charAt(unsigned int index) const { return operator[](index); } + void setCharAt(unsigned int index, char c) { (*this)[index] = c; } + + void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const { copy((char*)buf, bufsize, index); } + void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const + { getBytes((unsigned char *)buf, bufsize, index); } + + int indexOf( char ch ) const { return find(ch); } + int indexOf( char ch, unsigned int fromIndex ) const { return find(ch, fromIndex); } + int indexOf( const String &str ) const { return find(str); } + int indexOf( const String &str, unsigned int fromIndex ) const { return find(str, fromIndex); } + int lastIndexOf( char ch ) const { return rfind(ch); } + int lastIndexOf( char ch, unsigned int fromIndex ) const { return rfind(ch, fromIndex); } + int lastIndexOf( const String &str ) const { return rfind(str); } + int lastIndexOf( const String &str, unsigned int fromIndex ) const { return rfind(str, fromIndex); } + String substring( unsigned int beginIndex ) const { return String(substr(beginIndex)); } + String substring( unsigned int beginIndex, unsigned int endIndex ) const { return String(substr(beginIndex, endIndex)); } + + void replace(const String& target, const String& repl) { + int i = 0; + while ((i = find(target, i)) != npos) { + assign(substr(0, i) + repl + substr(i + target.length())); + i += repl.length(); + } + } + void replace(char target, char repl) { + replace(String(target), String(repl)); + } + void remove(unsigned int index) { assign(substr(0, index)); } + void remove(unsigned int index, unsigned int count) { assign(substr(0, index) + substr(min(length(), index + count), count)); } + void toLowerCase(void) { std::transform(begin(), end(), begin(), ::tolower); } + void toUpperCase(void) { std::transform(begin(), end(), begin(), ::toupper); } + + void trim(void) { + int b; + int e; + for (b = 0; b < length() && isSpace(charAt(b)); ++b); + for (e = length() - 1; e > b && isSpace(charAt(e)); --e); + assign(substr(b, e - b + 1)); + } + + long toInt(void) const { return std::stol(*this); } + float toFloat(void) const { return std::stof(*this); } + double toDouble(void) const { return std::stod(*this); } }; diff --git a/cpp/arduino/avr/pgmspace.h b/cpp/arduino/avr/pgmspace.h index cb83e57c..bb66b6e9 100644 --- a/cpp/arduino/avr/pgmspace.h +++ b/cpp/arduino/avr/pgmspace.h @@ -1,10 +1,9 @@ #pragma once - /* def d(var_raw) var = var_raw.split("_")[0] - out = "#define #{var}_P(...) #{var}(__VA_ARGS__)\n" + out = "#define #{var}_P(...) ::#{var}(__VA_ARGS__)\n" IO.popen('pbcopy', 'w') { |f| f << out } out end @@ -16,6 +15,7 @@ out.each { |l| puts d(l) } */ #include +#include #define PROGMEM @@ -49,46 +49,46 @@ out.each { |l| puts d(l) } #define pgm_read_ptr(x) (x) #define pgm_get_far_address(x) (x) -#define memchr_P(...) memchr(__VA_ARGS__) -#define memcmp_P(...) memcmp(__VA_ARGS__) -#define memccpy_P(...) memccpy(__VA_ARGS__) -#define memcpy_P(...) memcpy(__VA_ARGS__) -#define memmem_P(...) memmem(__VA_ARGS__) -#define memrchr_P(...) memrchr(__VA_ARGS__) -#define strcat_P(...) strcat(__VA_ARGS__) -#define strchr_P(...) strchr(__VA_ARGS__) -#define strchrnul_P(...) strchrnul(__VA_ARGS__) -#define strcmp_P(...) strcmp(__VA_ARGS__) -#define strcpy_P(...) strcpy(__VA_ARGS__) -#define strcasecmp_P(...) strcasecmp(__VA_ARGS__) -#define strcasestr_P(...) strcasestr(__VA_ARGS__) -#define strcspn_P(...) strcspn(__VA_ARGS__) -#define strlcat_P(...) strlcat(__VA_ARGS__) -#define strlcpy_P(...) strlcpy(__VA_ARGS__) -#define strnlen_P(...) strnlen(__VA_ARGS__) -#define strncmp_P(...) strncmp(__VA_ARGS__) -#define strncasecmp_P(...) strncasecmp(__VA_ARGS__) -#define strncat_P(...) strncat(__VA_ARGS__) -#define strncpy_P(...) strncpy(__VA_ARGS__) -#define strpbrk_P(...) strpbrk(__VA_ARGS__) -#define strrchr_P(...) strrchr(__VA_ARGS__) -#define strsep_P(...) strsep(__VA_ARGS__) -#define strspn_P(...) strspn(__VA_ARGS__) -#define strstr_P(...) strstr(__VA_ARGS__) -#define strtok_P(...) strtok(__VA_ARGS__) -#define strtok_P(...) strtok(__VA_ARGS__) -#define strlen_P(...) strlen(__VA_ARGS__) -#define strnlen_P(...) strnlen(__VA_ARGS__) -#define memcpy_P(...) memcpy(__VA_ARGS__) -#define strcpy_P(...) strcpy(__VA_ARGS__) -#define strncpy_P(...) strncpy(__VA_ARGS__) -#define strcat_P(...) strcat(__VA_ARGS__) -#define strlcat_P(...) strlcat(__VA_ARGS__) -#define strncat_P(...) strncat(__VA_ARGS__) -#define strcmp_P(...) strcmp(__VA_ARGS__) -#define strncmp_P(...) strncmp(__VA_ARGS__) -#define strcasecmp_P(...) strcasecmp(__VA_ARGS__) -#define strncasecmp_P(...) strncasecmp(__VA_ARGS__) -#define strstr_P(...) strstr(__VA_ARGS__) -#define strlcpy_P(...) strlcpy(__VA_ARGS__) -#define memcmp_P(...) memcmp(__VA_ARGS__) +#define memchr_P(...) ::memchr(__VA_ARGS__) +#define memcmp_P(...) ::memcmp(__VA_ARGS__) +#define memccpy_P(...) ::memccpy(__VA_ARGS__) +#define memcpy_P(...) ::memcpy(__VA_ARGS__) +#define memmem_P(...) ::memmem(__VA_ARGS__) +#define memrchr_P(...) ::memrchr(__VA_ARGS__) +#define strcat_P(...) ::strcat(__VA_ARGS__) +#define strchr_P(...) ::strchr(__VA_ARGS__) +#define strchrnul_P(...) ::strchrnul(__VA_ARGS__) +#define strcmp_P(...) ::strcmp(__VA_ARGS__) +#define strcpy_P(...) ::strcpy(__VA_ARGS__) +#define strcasecmp_P(...) ::strcasecmp(__VA_ARGS__) +#define strcasestr_P(...) ::strcasestr(__VA_ARGS__) +#define strcspn_P(...) ::strcspn(__VA_ARGS__) +#define strlcat_P(...) ::strlcat(__VA_ARGS__) +#define strlcpy_P(...) ::strlcpy(__VA_ARGS__) +#define strnlen_P(...) ::strnlen(__VA_ARGS__) +#define strncmp_P(...) ::strncmp(__VA_ARGS__) +#define strncasecmp_P(...) ::strncasecmp(__VA_ARGS__) +#define strncat_P(...) ::strncat(__VA_ARGS__) +#define strncpy_P(...) ::strncpy(__VA_ARGS__) +#define strpbrk_P(...) ::strpbrk(__VA_ARGS__) +#define strrchr_P(...) ::strrchr(__VA_ARGS__) +#define strsep_P(...) ::strsep(__VA_ARGS__) +#define strspn_P(...) ::strspn(__VA_ARGS__) +#define strstr_P(...) ::strstr(__VA_ARGS__) +#define strtok_P(...) ::strtok(__VA_ARGS__) +#define strtok_P(...) ::strtok(__VA_ARGS__) +#define strlen_P(...) ::strlen(__VA_ARGS__) +#define strnlen_P(...) ::strnlen(__VA_ARGS__) +#define memcpy_P(...) ::memcpy(__VA_ARGS__) +#define strcpy_P(...) ::strcpy(__VA_ARGS__) +#define strncpy_P(...) ::strncpy(__VA_ARGS__) +#define strcat_P(...) ::strcat(__VA_ARGS__) +#define strlcat_P(...) ::strlcat(__VA_ARGS__) +#define strncat_P(...) ::strncat(__VA_ARGS__) +#define strcmp_P(...) ::strcmp(__VA_ARGS__) +#define strncmp_P(...) ::strncmp(__VA_ARGS__) +#define strcasecmp_P(...) ::strcasecmp(__VA_ARGS__) +#define strncasecmp_P(...) ::strncasecmp(__VA_ARGS__) +#define strstr_P(...) ::strstr(__VA_ARGS__) +#define strlcpy_P(...) ::strlcpy(__VA_ARGS__) +#define memcmp_P(...) ::memcmp(__VA_ARGS__) diff --git a/cpp/arduino/ci/Queue.h b/cpp/arduino/ci/Queue.h index e25b1d7d..87a0cf49 100644 --- a/cpp/arduino/ci/Queue.h +++ b/cpp/arduino/ci/Queue.h @@ -30,9 +30,9 @@ class Queue { inline bool empty() const { return 0 == mSize; } - const T& front() const { return empty() ? mNil : mFront->data; } + T front() const { return empty() ? mNil : mFront->data; } - const T& back() const { return empty() ? mNil : mBack->data; } + T back() const { return empty() ? mNil : mBack->data; } bool push(const T& v) { diff --git a/cpp/unittest/ArduinoUnitTests.h b/cpp/unittest/ArduinoUnitTests.h index a3a1ac7d..0c5521eb 100644 --- a/cpp/unittest/ArduinoUnitTests.h +++ b/cpp/unittest/ArduinoUnitTests.h @@ -113,8 +113,8 @@ class Test static const int RESULT_FAIL = 2; static const int RESULT_SKIP = 3; - const inline char *name() { return mName; } - const inline int result() { return mResult; } + inline const char *name() const { return mName; } + inline int result() const { return mResult; } Test(const char* _name) : mName(_name) { mResult = RESULT_NONE; diff --git a/cpp/unittest/Compare.h b/cpp/unittest/Compare.h index 1fefd1cb..3ae331fb 100644 --- a/cpp/unittest/Compare.h +++ b/cpp/unittest/Compare.h @@ -1,5 +1,6 @@ #pragma once -#include "string.h" +#include +#include template < typename A, typename B > struct Compare { @@ -34,17 +35,250 @@ template < typename A, typename B > struct Compare return !(a struct Compare; +template < > struct Compare; +#if defined(F) +template < > struct Compare; +#endif +template < > struct Compare; +template < size_t M > struct Compare; +template < > struct Compare; template < > struct Compare; +#if defined(F) +template < > struct Compare; +#endif template < > struct Compare; -template < long M > struct Compare; +template < size_t M > struct Compare; +#if defined(F) +template < > struct Compare; +#endif +#if defined(F) +template < > struct Compare; +#endif +#if defined(F) +template < > struct Compare; +#endif +#if defined(F) +template < > struct Compare; +#endif +#if defined(F) +template < size_t M > struct Compare; +#endif +template < > struct Compare; template < > struct Compare; +#if defined(F) +template < > struct Compare; +#endif template < > struct Compare; -template < long M > struct Compare; -template < long N > struct Compare; -template < long N > struct Compare; -template < long N, long M > struct Compare; +template < size_t M > struct Compare; +template < size_t N > struct Compare; +template < size_t N > struct Compare; +#if defined(F) +template < size_t N > struct Compare; +#endif +template < size_t N > struct Compare; +template < size_t N, size_t M > struct Compare; +template < > struct Compare +{ + inline static int between(const String &a,const String &b) + { + return a.compareTo(b); + } // between + inline static bool equal(const String &a,const String &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const String &a,const String &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const String &a,const String &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const String &a,const String &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const String &a,const String &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const String &a,const String &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +template < > struct Compare +{ + inline static int between(const String &a,const char * const &b) + { + return a.compareTo(b); + } // between + inline static bool equal(const String &a,const char * const &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const String &a,const char * const &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const String &a,const char * const &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const String &a,const char * const &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const String &a,const char * const &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const String &a,const char * const &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +#if defined(F) +template < > struct Compare +{ + inline static int between(const String &a,const __FlashStringHelper * const &b) + { + uint8_t a_buf[4],b_buf[4]; + uint16_t i=0; + for (;;) { + uint8_t j=(i%4); + if (j == 0) { + a.getBytes(a_buf,4,i); + memcpy_P(b_buf,((const char *)b)+i,4); + } + if (a_buf[j] < b_buf[j]) return -1; + if (a_buf[j] > b_buf[j]) return 1; + if (a_buf[j] == 0) return 0; + ++i; + } + } // between + inline static bool equal(const String &a,const __FlashStringHelper * const &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const String &a,const __FlashStringHelper * const &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const String &a,const __FlashStringHelper * const &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const String &a,const __FlashStringHelper * const &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const String &a,const __FlashStringHelper * const &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const String &a,const __FlashStringHelper * const &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +#endif +template < > struct Compare +{ + inline static int between(const String &a,char * const &b) + { + return a.compareTo(b); + } // between + inline static bool equal(const String &a,char * const &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const String &a,char * const &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const String &a,char * const &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const String &a,char * const &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const String &a,char * const &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const String &a,char * const &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +template < size_t M > struct Compare +{ + inline static int between(const String &a,const char (&b)[M]) + { + return a.compareTo(b); + } // between + inline static bool equal(const String &a,const char (&b)[M]) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const String &a,const char (&b)[M]) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const String &a,const char (&b)[M]) + { + return between(a,b) < 0; + } // less + inline static bool more(const String &a,const char (&b)[M]) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const String &a,const char (&b)[M]) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const String &a,const char (&b)[M]) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +template < > struct Compare +{ + inline static int between(const char * const &a,const String &b) + { + return -b.compareTo(a); + } // between + inline static bool equal(const char * const &a,const String &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const char * const &a,const String &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const char * const &a,const String &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const char * const &a,const String &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const char * const &a,const String &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const char * const &a,const String &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; template < > struct Compare { inline static int between(const char * const &a,const char * const &b) @@ -76,6 +310,39 @@ template < > struct Compare return between(a,b) >= 0; } // moreOrEqual }; +#if defined(F) +template < > struct Compare +{ + inline static int between(const char * const &a,const __FlashStringHelper * const &b) + { + return strcmp_P(a,(const char *)b); + } // between + inline static bool equal(const char * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const char * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const char * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const char * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const char * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const char * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +#endif template < > struct Compare { inline static int between(const char * const &a,char * const &b) @@ -107,7 +374,7 @@ template < > struct Compare return between(a,b) >= 0; } // moreOrEqual }; -template < long M > struct Compare +template < size_t M > struct Compare { inline static int between(const char * const &a,const char (&b)[M]) { @@ -138,6 +405,215 @@ template < long M > struct Compare return between(a,b) >= 0; } // moreOrEqual }; +#if defined(F) +template < > struct Compare +{ + inline static int between(const __FlashStringHelper * const &a,const String &b) + { + return -Compare < String,const __FlashStringHelper * >::between(b,a); + } // between + inline static bool equal(const __FlashStringHelper * const &a,const String &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const __FlashStringHelper * const &a,const String &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const __FlashStringHelper * const &a,const String &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const __FlashStringHelper * const &a,const String &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const __FlashStringHelper * const &a,const String &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const __FlashStringHelper * const &a,const String &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +#endif +#if defined(F) +template < > struct Compare +{ + inline static int between(const __FlashStringHelper * const &a,const char * const &b) + { + return -strcmp_P(b,(const char *)a); + } // between + inline static bool equal(const __FlashStringHelper * const &a,const char * const &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const __FlashStringHelper * const &a,const char * const &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const __FlashStringHelper * const &a,const char * const &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const __FlashStringHelper * const &a,const char * const &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const __FlashStringHelper * const &a,const char * const &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const __FlashStringHelper * const &a,const char * const &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +#endif +#if defined(F) +template < > struct Compare +{ + inline static int between(const __FlashStringHelper * const &a,const __FlashStringHelper * const &b) + { + uint8_t a_buf[4],b_buf[4]; + uint16_t i=0; + + for (;;) { + uint8_t j=(i%4); + if (j == 0) { + memcpy_P(a_buf,((const char *)a)+i,4); + memcpy_P(b_buf,((const char *)b)+i,4); + } + if (a_buf[j] < b_buf[j]) return -1; + if (a_buf[j] > b_buf[j]) return 1; + if (a_buf[j] == 0) return 0; + ++i; + } + } // between + inline static bool equal(const __FlashStringHelper * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const __FlashStringHelper * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const __FlashStringHelper * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const __FlashStringHelper * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const __FlashStringHelper * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const __FlashStringHelper * const &a,const __FlashStringHelper * const &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +#endif +#if defined(F) +template < > struct Compare +{ + inline static int between(const __FlashStringHelper * const &a,char * const &b) + { + return -strcmp_P(b,(const char *)a); + } // between + inline static bool equal(const __FlashStringHelper * const &a,char * const &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const __FlashStringHelper * const &a,char * const &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const __FlashStringHelper * const &a,char * const &b) + { + return between(a,b) < 0; + } // less + inline static bool more(const __FlashStringHelper * const &a,char * const &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const __FlashStringHelper * const &a,char * const &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const __FlashStringHelper * const &a,char * const &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +#endif +#if defined(F) +template < size_t M > struct Compare +{ + inline static int between(const __FlashStringHelper * const &a,const char (&b)[M]) + { + return -strcmp_P(b,(const char *)a); + } // between + inline static bool equal(const __FlashStringHelper * const &a,const char (&b)[M]) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(const __FlashStringHelper * const &a,const char (&b)[M]) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(const __FlashStringHelper * const &a,const char (&b)[M]) + { + return between(a,b) < 0; + } // less + inline static bool more(const __FlashStringHelper * const &a,const char (&b)[M]) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(const __FlashStringHelper * const &a,const char (&b)[M]) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(const __FlashStringHelper * const &a,const char (&b)[M]) + { + return between(a,b) >= 0; + } // moreOrEqual +}; +#endif +template < > struct Compare +{ + inline static int between(char * const &a,const String &b) + { + return -b.compareTo(a); + } // between + inline static bool equal(char * const &a,const String &b) + { + return between(a,b) == 0; + } // equal + inline static bool notEqual(char * const &a,const String &b) + { + return between(a,b) != 0; + } // notEqual + inline static bool less(char * const &a,const String &b) + { + return between(a,b) < 0; + } // less + inline static bool more(char * const &a,const String &b) + { + return between(a,b) > 0; + } // more + inline static bool lessOrEqual(char * const &a,const String &b) + { + return between(a,b) <= 0; + } // lessOrEqual + inline static bool moreOrEqual(char * const &a,const String &b) + { + return between(a,b) >= 0; + } // moreOrEqual +}; template < > struct Compare { inline static int between(char * const &a,const char * const &b) @@ -169,255 +645,258 @@ template < > struct Compare return between(a,b) >= 0; } // moreOrEqual }; -template < > struct Compare +#if defined(F) +template < > struct Compare { - inline static int between(char * const &a,char * const &b) + inline static int between(char * const &a,const __FlashStringHelper * const &b) { - return strcmp(a,b); + return strcmp_P(a,(const char *)b); } // between - inline static bool equal(char * const &a,char * const &b) + inline static bool equal(char * const &a,const __FlashStringHelper * const &b) { return between(a,b) == 0; } // equal - inline static bool notEqual(char * const &a,char * const &b) + inline static bool notEqual(char * const &a,const __FlashStringHelper * const &b) { return between(a,b) != 0; } // notEqual - inline static bool less(char * const &a,char * const &b) + inline static bool less(char * const &a,const __FlashStringHelper * const &b) { return between(a,b) < 0; } // less - inline static bool more(char * const &a,char * const &b) + inline static bool more(char * const &a,const __FlashStringHelper * const &b) { return between(a,b) > 0; } // more - inline static bool lessOrEqual(char * const &a,char * const &b) + inline static bool lessOrEqual(char * const &a,const __FlashStringHelper * const &b) { return between(a,b) <= 0; } // lessOrEqual - inline static bool moreOrEqual(char * const &a,char * const &b) + inline static bool moreOrEqual(char * const &a,const __FlashStringHelper * const &b) { return between(a,b) >= 0; } // moreOrEqual }; -template < long M > struct Compare +#endif +template < > struct Compare { - inline static int between(char * const &a,const char (&b)[M]) + inline static int between(char * const &a,char * const &b) { return strcmp(a,b); } // between - inline static bool equal(char * const &a,const char (&b)[M]) + inline static bool equal(char * const &a,char * const &b) { return between(a,b) == 0; } // equal - inline static bool notEqual(char * const &a,const char (&b)[M]) + inline static bool notEqual(char * const &a,char * const &b) { return between(a,b) != 0; } // notEqual - inline static bool less(char * const &a,const char (&b)[M]) + inline static bool less(char * const &a,char * const &b) { return between(a,b) < 0; } // less - inline static bool more(char * const &a,const char (&b)[M]) + inline static bool more(char * const &a,char * const &b) { return between(a,b) > 0; } // more - inline static bool lessOrEqual(char * const &a,const char (&b)[M]) + inline static bool lessOrEqual(char * const &a,char * const &b) { return between(a,b) <= 0; } // lessOrEqual - inline static bool moreOrEqual(char * const &a,const char (&b)[M]) + inline static bool moreOrEqual(char * const &a,char * const &b) { return between(a,b) >= 0; } // moreOrEqual }; -template < long N > struct Compare +template < size_t M > struct Compare { - inline static int between(const char (&a)[N],const char * const &b) + inline static int between(char * const &a,const char (&b)[M]) { return strcmp(a,b); } // between - inline static bool equal(const char (&a)[N],const char * const &b) + inline static bool equal(char * const &a,const char (&b)[M]) { return between(a,b) == 0; } // equal - inline static bool notEqual(const char (&a)[N],const char * const &b) + inline static bool notEqual(char * const &a,const char (&b)[M]) { return between(a,b) != 0; } // notEqual - inline static bool less(const char (&a)[N],const char * const &b) + inline static bool less(char * const &a,const char (&b)[M]) { return between(a,b) < 0; } // less - inline static bool more(const char (&a)[N],const char * const &b) + inline static bool more(char * const &a,const char (&b)[M]) { return between(a,b) > 0; } // more - inline static bool lessOrEqual(const char (&a)[N],const char * const &b) + inline static bool lessOrEqual(char * const &a,const char (&b)[M]) { return between(a,b) <= 0; } // lessOrEqual - inline static bool moreOrEqual(const char (&a)[N],const char * const &b) + inline static bool moreOrEqual(char * const &a,const char (&b)[M]) { return between(a,b) >= 0; } // moreOrEqual }; -template < long N > struct Compare +template < size_t N > struct Compare { - inline static int between(const char (&a)[N],char * const &b) + inline static int between(const char (&a)[N],const String &b) { - return strcmp(a,b); + return -b.compareTo(a); } // between - inline static bool equal(const char (&a)[N],char * const &b) + inline static bool equal(const char (&a)[N],const String &b) { return between(a,b) == 0; } // equal - inline static bool notEqual(const char (&a)[N],char * const &b) + inline static bool notEqual(const char (&a)[N],const String &b) { return between(a,b) != 0; } // notEqual - inline static bool less(const char (&a)[N],char * const &b) + inline static bool less(const char (&a)[N],const String &b) { return between(a,b) < 0; } // less - inline static bool more(const char (&a)[N],char * const &b) + inline static bool more(const char (&a)[N],const String &b) { return between(a,b) > 0; } // more - inline static bool lessOrEqual(const char (&a)[N],char * const &b) + inline static bool lessOrEqual(const char (&a)[N],const String &b) { return between(a,b) <= 0; } // lessOrEqual - inline static bool moreOrEqual(const char (&a)[N],char * const &b) + inline static bool moreOrEqual(const char (&a)[N],const String &b) { return between(a,b) >= 0; } // moreOrEqual }; -template < long N, long M > struct Compare +template < size_t N > struct Compare { - inline static int between(const char (&a)[N],const char (&b)[M]) + inline static int between(const char (&a)[N],const char * const &b) { return strcmp(a,b); } // between - inline static bool equal(const char (&a)[N],const char (&b)[M]) + inline static bool equal(const char (&a)[N],const char * const &b) { return between(a,b) == 0; } // equal - inline static bool notEqual(const char (&a)[N],const char (&b)[M]) + inline static bool notEqual(const char (&a)[N],const char * const &b) { return between(a,b) != 0; } // notEqual - inline static bool less(const char (&a)[N],const char (&b)[M]) + inline static bool less(const char (&a)[N],const char * const &b) { return between(a,b) < 0; } // less - inline static bool more(const char (&a)[N],const char (&b)[M]) + inline static bool more(const char (&a)[N],const char * const &b) { return between(a,b) > 0; } // more - inline static bool lessOrEqual(const char (&a)[N],const char (&b)[M]) + inline static bool lessOrEqual(const char (&a)[N],const char * const &b) { return between(a,b) <= 0; } // lessOrEqual - inline static bool moreOrEqual(const char (&a)[N],const char (&b)[M]) + inline static bool moreOrEqual(const char (&a)[N],const char * const &b) { return between(a,b) >= 0; } // moreOrEqual }; -template < > struct Compare +#if defined(F) +template < size_t N > struct Compare { - inline static int between(bool a, bool b) + inline static int between(const char (&a)[N],const __FlashStringHelper * const &b) { - return b ? (a ? 0 : -1) : (a ? 1 : 0); + return strcmp_P(a,(const char *)b); } // between - inline static bool equal(bool a, bool b) + inline static bool equal(const char (&a)[N],const __FlashStringHelper * const &b) { return between(a,b) == 0; } // equal - inline static bool notEqual(bool a, bool b) + inline static bool notEqual(const char (&a)[N],const __FlashStringHelper * const &b) { return between(a,b) != 0; } // notEqual - inline static bool less(bool a, bool b) + inline static bool less(const char (&a)[N],const __FlashStringHelper * const &b) { return between(a,b) < 0; } // less - inline static bool more(bool a, bool b) + inline static bool more(const char (&a)[N],const __FlashStringHelper * const &b) { return between(a,b) > 0; } // more - inline static bool lessOrEqual(bool a, bool b) + inline static bool lessOrEqual(const char (&a)[N],const __FlashStringHelper * const &b) { return between(a,b) <= 0; } // lessOrEqual - inline static bool moreOrEqual(bool a, bool b) + inline static bool moreOrEqual(const char (&a)[N],const __FlashStringHelper * const &b) { return between(a,b) >= 0; } // moreOrEqual }; -template struct Compare +#endif +template < size_t N > struct Compare { - inline static int between(bool a, T b) + inline static int between(const char (&a)[N],char * const &b) { - return b ? (a ? 0 : -1) : (a ? 1 : 0); + return strcmp(a,b); } // between - inline static bool equal(bool a, T b) + inline static bool equal(const char (&a)[N],char * const &b) { return between(a,b) == 0; } // equal - inline static bool notEqual(bool a, T b) + inline static bool notEqual(const char (&a)[N],char * const &b) { return between(a,b) != 0; } // notEqual - inline static bool less(bool a, T b) + inline static bool less(const char (&a)[N],char * const &b) { return between(a,b) < 0; } // less - inline static bool more(bool a, T b) + inline static bool more(const char (&a)[N],char * const &b) { return between(a,b) > 0; } // more - inline static bool lessOrEqual(bool a, T b) + inline static bool lessOrEqual(const char (&a)[N],char * const &b) { return between(a,b) <= 0; } // lessOrEqual - inline static bool moreOrEqual(bool a, T b) + inline static bool moreOrEqual(const char (&a)[N],char * const &b) { return between(a,b) >= 0; } // moreOrEqual }; -template struct Compare +template < size_t N, size_t M > struct Compare { - inline static int between(T a, bool b) + inline static int between(const char (&a)[N],const char (&b)[M]) { - return b ? (a ? 0 : -1) : (a ? 1 : 0); + return strcmp(a,b); } // between - inline static bool equal(T a, bool b) + inline static bool equal(const char (&a)[N],const char (&b)[M]) { return between(a,b) == 0; } // equal - inline static bool notEqual(T a, bool b) + inline static bool notEqual(const char (&a)[N],const char (&b)[M]) { return between(a,b) != 0; } // notEqual - inline static bool less(T a, bool b) + inline static bool less(const char (&a)[N],const char (&b)[M]) { return between(a,b) < 0; } // less - inline static bool more(T a, bool b) + inline static bool more(const char (&a)[N],const char (&b)[M]) { return between(a,b) > 0; } // more - inline static bool lessOrEqual(T a, bool b) + inline static bool lessOrEqual(const char (&a)[N],const char (&b)[M]) { return between(a,b) <= 0; } // lessOrEqual - inline static bool moreOrEqual(T a, bool b) + inline static bool moreOrEqual(const char (&a)[N],const char (&b)[M]) { return between(a,b) >= 0; } // moreOrEqual }; - template int compareBetween(const A &a, const B &b) { return Compare::between(a,b); } template bool compareEqual(const A &a, const B &b) { return Compare::equal(a,b); } template bool compareNotEqual(const A &a, const B &b) { return Compare::notEqual(a,b); } diff --git a/exe/arduino_ci_remote.rb b/exe/arduino_ci_remote.rb index 6a3d2a9e..19b39587 100755 --- a/exe/arduino_ci_remote.rb +++ b/exe/arduino_ci_remote.rb @@ -21,11 +21,18 @@ def terminate(final = nil) end # make a nice status line for an action and react to the action -def perform_action(message, on_fail_msg, abort_on_fail) - line = "#{message}..." - print line +def perform_action(message, multiline, on_fail_msg, abort_on_fail) + line = "#{message}... " + endline = "...#{message} " + if multiline + puts line + else + print line + end result = yield mark = result ? "✓" : "✗" + # if multline, put checkmark at full width + print endline if multiline puts mark.rjust(WIDTH - line.length, " ") unless result puts on_fail_msg unless on_fail_msg.nil? @@ -38,12 +45,17 @@ def perform_action(message, on_fail_msg, abort_on_fail) # Make a nice status for something that defers any failure code until script exit def attempt(message, &block) - perform_action(message, nil, false, &block) + perform_action(message, false, nil, false, &block) +end + +# Make a nice status for something that defers any failure code until script exit +def attempt_multiline(message, &block) + perform_action(message, true, nil, false, &block) end # Make a nice status for something that kills the script immediately on failure def assure(message, &block) - perform_action(message, "This may indicate a problem with ArduinoCI!", true, &block) + perform_action(message, false, "This may indicate a problem with ArduinoCI!", true, &block) end # initialize command and config @@ -56,6 +68,14 @@ def assure(message, &block) cpp_library = ArduinoCI::CppLibrary.new(installed_library_path) attempt("Library installed at #{installed_library_path}") { true } +# check GCC +attempt_multiline("Checking GCC version") do + version = cpp_library.gcc_version + next nil unless version + puts version.split("\n").map { |l| " #{l}" }.join("\n") + version +end + # gather up all required boards so we can install them up front. # start with the "platforms to unittest" and add the examples # while we're doing that, get the aux libraries as well @@ -101,7 +121,7 @@ def assure(message, &block) last_board = board cpp_library.test_files.each do |unittest_path| unittest_name = File.basename(unittest_path) - attempt("Unit testing #{unittest_name}") do + attempt_multiline("Unit testing #{unittest_name}") do exe = cpp_library.build_for_test_with_configuration( unittest_path, config.aux_libraries_for_unittest, diff --git a/lib/arduino_ci/arduino_cmd.rb b/lib/arduino_ci/arduino_cmd.rb index be6f2ad5..d1e16a3a 100644 --- a/lib/arduino_ci/arduino_cmd.rb +++ b/lib/arduino_ci/arduino_cmd.rb @@ -114,12 +114,18 @@ def set_pref(key, value) end # run the arduino command - def _run(*args, **kwargs) + # @return [bool] whether the command succeeded + def _run_and_output(*args, **kwargs) raise "Ian needs to implement this in a subclass #{args} #{kwargs}" end - # build and run the arduino command - def run(*args, **kwargs) + # run the arduino command + # @return [Hash] keys for :success, :out, and :err + def _run_and_capture(*args, **kwargs) + raise "Ian needs to implement this in a subclass #{args} #{kwargs}" + end + + def _wrap_run(work_fn, *args, **kwargs) # do some work to extract & merge environment variables if they exist has_env = !args.empty? && args[0].class == Hash env_vars = has_env ? args[0] : {} @@ -129,26 +135,21 @@ def run(*args, **kwargs) shell_vars = env_vars.map { |k, v| "#{k}=#{v}" }.join(" ") @last_msg = " $ #{shell_vars} #{full_args.join(' ')}" - _run(*full_cmd, **kwargs) + work_fn.call(*full_cmd, **kwargs) + end + + # build and run the arduino command + def run_and_output(*args, **kwargs) + _wrap_run((proc { |*a, **k| _run_and_output(*a, **k) }), *args, **kwargs) end # run a command and capture its output # @return [Hash] {:out => String, :err => String, :success => bool} def run_and_capture(*args, **kwargs) - pipe_out, pipe_out_wr = IO.pipe - pipe_err, pipe_err_wr = IO.pipe - our_kwargs = { out: pipe_out_wr, err: pipe_err_wr } - eventual_kwargs = our_kwargs.merge(kwargs) - success = run(*args, **eventual_kwargs) - pipe_out_wr.close - pipe_err_wr.close - str_out = pipe_out.read - str_err = pipe_err.read - pipe_out.close - pipe_err.close - @last_err = str_err - @last_out = str_out - { out: str_out, err: str_err, success: success } + ret = _wrap_run((proc { |*a, **k| _run_and_capture(*a, **k) }), *args, **kwargs) + @last_err = ret[:err] + @last_out = ret[:out] + ret end # run a command and don't capture its output, but use the same signature diff --git a/lib/arduino_ci/arduino_cmd_linux.rb b/lib/arduino_ci/arduino_cmd_linux.rb index a31d6598..04888077 100644 --- a/lib/arduino_ci/arduino_cmd_linux.rb +++ b/lib/arduino_ci/arduino_cmd_linux.rb @@ -39,8 +39,15 @@ def _lib_dir end # run the arduino command - def _run(*args, **kwargs) - @display_mgr.run(*args, **kwargs) + # @return [bool] whether the command succeeded + def _run_and_output(*args, **kwargs) + @display_mgr.run_and_output(*args, **kwargs) + end + + # run the arduino command + # @return [Hash] keys for :success, :out, and :err + def _run_and_capture(*args, **kwargs) + @display_mgr.run_and_capture(*args, **kwargs) end def run_with_gui_guess(message, *args, **kwargs) diff --git a/lib/arduino_ci/arduino_cmd_linux_builder.rb b/lib/arduino_ci/arduino_cmd_linux_builder.rb index 4740489d..486f85f0 100644 --- a/lib/arduino_ci/arduino_cmd_linux_builder.rb +++ b/lib/arduino_ci/arduino_cmd_linux_builder.rb @@ -21,10 +21,15 @@ def _lib_dir end # run the arduino command - # @param [Array] Arguments for the run command - # @return [bool] Whether the command succeeded - def _run(*args, **kwargs) - Host.run(*args, **kwargs) + # @return [bool] whether the command succeeded + def _run_and_output(*args, **kwargs) + Host.run_and_output(*args, **kwargs) + end + + # run the arduino command + # @return [Hash] keys for :success, :out, and :err + def _run_and_capture(*args, **kwargs) + Host.run_and_capture(*args, **kwargs) end end diff --git a/lib/arduino_ci/arduino_cmd_osx.rb b/lib/arduino_ci/arduino_cmd_osx.rb index 68b865bf..b8d7ad3e 100644 --- a/lib/arduino_ci/arduino_cmd_osx.rb +++ b/lib/arduino_ci/arduino_cmd_osx.rb @@ -14,8 +14,15 @@ class ArduinoCmdOSX < ArduinoCmd flag :verify, "--verify" # run the arduino command - def _run(*args, **kwargs) - Host.run(*args, **kwargs) + # @return [bool] whether the command succeeded + def _run_and_output(*args, **kwargs) + Host.run_and_output(*args, **kwargs) + end + + # run the arduino command + # @return [Hash] keys for :success, :out, and :err + def _run_and_capture(*args, **kwargs) + Host.run_and_capture(*args, **kwargs) end def _lib_dir diff --git a/lib/arduino_ci/ci_config.rb b/lib/arduino_ci/ci_config.rb index 38a0131d..712db8a0 100644 --- a/lib/arduino_ci/ci_config.rb +++ b/lib/arduino_ci/ci_config.rb @@ -200,12 +200,14 @@ def package_url(package) # platforms to build [the examples on] # @return [Array] The platforms to build def platforms_to_build + return [] if @compile_info[:platforms].nil? @compile_info[:platforms] end # platforms to unit test [the tests on] # @return [Array] The platforms to unit test on def platforms_to_unittest + return [] if @unittest_info[:platforms].nil? @unittest_info[:platforms] end diff --git a/lib/arduino_ci/cpp_library.rb b/lib/arduino_ci/cpp_library.rb index 3ba378e5..f6904bf9 100644 --- a/lib/arduino_ci/cpp_library.rb +++ b/lib/arduino_ci/cpp_library.rb @@ -108,23 +108,20 @@ def header_dirs # wrapper for the GCC command def run_gcc(*args, **kwargs) - pipe_out, pipe_out_wr = IO.pipe - pipe_err, pipe_err_wr = IO.pipe full_args = ["g++"] + args @last_cmd = " $ #{full_args.join(' ')}" - our_kwargs = { out: pipe_out_wr, err: pipe_err_wr } - eventual_kwargs = our_kwargs.merge(kwargs) - success = Host.run(*full_args, **eventual_kwargs) - pipe_out_wr.close - pipe_err_wr.close - str_out = pipe_out.read - str_err = pipe_err.read - pipe_out.close - pipe_err.close - @last_err = str_err - @last_out = str_out - success + ret = Host.run_and_capture(*full_args, **kwargs) + @last_err = ret[:err] + @last_out = ret[:out] + ret[:success] + end + + # Return the GCC version + # @return [String] the version reported by `gcc -v` + def gcc_version + return nil unless run_gcc("-v") + @last_err end # GCC command line arguments for including aux libraries @@ -207,7 +204,7 @@ def run_test_file(executable) @last_cmd = executable @last_out = "" @last_err = "" - Host.run(executable) + Host.run_and_output(executable) end end diff --git a/lib/arduino_ci/display_manager.rb b/lib/arduino_ci/display_manager.rb index 2445fd09..05f8189b 100644 --- a/lib/arduino_ci/display_manager.rb +++ b/lib/arduino_ci/display_manager.rb @@ -150,10 +150,8 @@ def with_display end end - # run a command in a display - # @return [bool] - def run(*args, **kwargs) - ret = false + def wrap_run(work_fn, *args, **kwargs) + ret = nil # do some work to extract & merge environment variables if they exist has_env = !args.empty? && args[0].class == Hash with_display do |env_vars| @@ -161,15 +159,21 @@ def run(*args, **kwargs) env_vars.merge!(args[0]) if has_env actual_args = has_env ? args[1..-1] : args # need to shift over if we extracted args full_cmd = env_vars.empty? ? actual_args : [env_vars] + actual_args - ret = Host.run(*full_cmd, **kwargs) + ret = work_fn.call(*full_cmd, **kwargs) end ret end - # run a command in a display with no output + # run a command in a display, outputting to stdout + # @return [bool] + def run_and_output(*args, **kwargs) + wrap_run((proc { |*a, **k| Host.run_and_output(*a, **k) }), *args, **kwargs) + end + + # run a command in a display, capturing output # @return [bool] - def run_silent(*args) - run(*args, out: File::NULL, err: File::NULL) + def run_and_capture(*args, **kwargs) + wrap_run((proc { |*a, **k| Host.run_and_capture(*a, **k) }), *args, **kwargs) end # @return [Hash] the environment variables for the display diff --git a/lib/arduino_ci/host.rb b/lib/arduino_ci/host.rb index 34819406..7a2983e6 100644 --- a/lib/arduino_ci/host.rb +++ b/lib/arduino_ci/host.rb @@ -1,4 +1,5 @@ require 'os' +require 'open3' module ArduinoCI @@ -20,8 +21,12 @@ def self.which(cmd) nil end - # run a command in a display - def self.run(*args, **kwargs) + def self.run_and_capture(*args, **kwargs) + stdout, stderr, status = Open3.capture3(*args, **kwargs) + { out: stdout, err: stderr, success: status.exitstatus.zero? } + end + + def self.run_and_output(*args, **kwargs) system(*args, **kwargs) end