|
- /* Arduino SdFat Library
- * Copyright (C) 2012 by William Greiman
- *
- * This file is part of the Arduino SdFat Library
- *
- * This Library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the Arduino SdFat Library. If not, see
- * <http://www.gnu.org/licenses/>.
- */
- #include <float.h>
- #include <istream.h>
- //------------------------------------------------------------------------------
- /**
- * Extract a character if one is available.
- *
- * \return The character or -1 if a failure occurs. A failure is indicated
- * by the stream state.
- */
- int istream::get() {
- int c;
- m_gcount = 0;
- c = getch();
- if (c < 0) {
- setstate(failbit);
- } else {
- m_gcount = 1;
- }
- return c;
- }
- //------------------------------------------------------------------------------
- /**
- * Extract a character if one is available.
- *
- * \param[out] c location to receive the extracted character.
- *
- * \return always returns *this. A failure is indicated by the stream state.
- */
- istream& istream::get(char& c) {
- int tmp = get();
- if (tmp >= 0) c = tmp;
- return *this;
- }
- //------------------------------------------------------------------------------
- /**
- * Extract characters.
- *
- * \param[out] str Location to receive extracted characters.
- * \param[in] n Size of str.
- * \param[in] delim Delimiter
- *
- * Characters are extracted until extraction fails, n is less than 1,
- * n-1 characters are extracted, or the next character equals
- * \a delim (delim is not extracted). If no characters are extracted
- * failbit is set. If end-of-file occurs the eofbit is set.
- *
- * \return always returns *this. A failure is indicated by the stream state.
- */
- istream& istream::get(char *str, streamsize n, char delim) {
- int c;
- FatPos_t pos;
- m_gcount = 0;
- while ((m_gcount + 1) < n) {
- c = getch(&pos);
- if (c < 0) {
- break;
- }
- if (c == delim) {
- setpos(&pos);
- break;
- }
- str[m_gcount++] = c;
- }
- if (n > 0) str[m_gcount] = '\0';
- if (m_gcount == 0) setstate(failbit);
- return *this;
- }
- //------------------------------------------------------------------------------
- void istream::getBool(bool *b) {
- if ((flags() & boolalpha) == 0) {
- getNumber(b);
- return;
- }
- PGM_P truePtr = PSTR("true");
- PGM_P falsePtr = PSTR("false");
- const uint8_t true_len = 4;
- const uint8_t false_len = 5;
- bool trueOk = true;
- bool falseOk = true;
- uint8_t i = 0;
- int c = readSkip();
- while (1) {
- falseOk = falseOk && c == pgm_read_byte(falsePtr + i);
- trueOk = trueOk && c == pgm_read_byte(truePtr + i);
- if (trueOk == false && falseOk == false) break;
- i++;
- if (trueOk && i == true_len) {
- *b = true;
- return;
- }
- if (falseOk && i == false_len) {
- *b = false;
- return;
- }
- c = getch();
- }
- setstate(failbit);
- }
- //------------------------------------------------------------------------------
- void istream::getChar(char* ch) {
- int16_t c = readSkip();
- if (c < 0) {
- setstate(failbit);
- } else {
- *ch = c;
- }
- }
- //------------------------------------------------------------------------------
- //
- // http://www.exploringbinary.com/category/numbers-in-computers/
- //
- int16_t const EXP_LIMIT = 100;
- static const uint32_t uint32_max = (uint32_t)-1;
- bool istream::getDouble(double* value) {
- bool got_digit = false;
- bool got_dot = false;
- bool neg;
- int16_t c;
- bool expNeg = false;
- int16_t exp = 0;
- int16_t fracExp = 0;
- uint32_t frac = 0;
- FatPos_t endPos;
- double pow10;
- double v;
-
- getpos(&endPos);
- c = readSkip();
- neg = c == '-';
- if (c == '-' || c == '+') {
- c = getch();
- }
- while (1) {
- if (isdigit(c)) {
- got_digit = true;
- if (frac < uint32_max/10) {
- frac = frac * 10 + (c - '0');
- if (got_dot) fracExp--;
- } else {
- if (!got_dot) fracExp++;
- }
- } else if (!got_dot && c == '.') {
- got_dot = true;
- } else {
- break;
- }
- if (fracExp < -EXP_LIMIT || fracExp > EXP_LIMIT) goto fail;
- c = getch(&endPos);
- }
- if (!got_digit) goto fail;
- if (c == 'e' || c == 'E') {
- c = getch();
- expNeg = c == '-';
- if (c == '-' || c == '+') {
- c = getch();
- }
- while (isdigit(c)) {
- if (exp > EXP_LIMIT) goto fail;
- exp = exp * 10 + (c - '0');
- c = getch(&endPos);
- }
- }
- v = static_cast<double>(frac);
- exp = expNeg ? fracExp - exp : fracExp + exp;
- expNeg = exp < 0;
- if (expNeg) exp = -exp;
- pow10 = 10.0;
- while (exp) {
- if (exp & 1) {
- if (expNeg) {
- // check for underflow
- if (v < FLT_MIN * pow10 && frac != 0) goto fail;
- v /= pow10;
- } else {
- // check for overflow
- if (v > FLT_MAX / pow10) goto fail;
- v *= pow10;
- }
- }
- pow10 *= pow10;
- exp >>= 1;
- }
- setpos(&endPos);
- *value = neg ? -v : v;
- return true;
-
- fail:
- // error restore position to last good place
- setpos(&endPos);
- setstate(failbit);
- return false;
- }
- //------------------------------------------------------------------------------
- /**
- * Extract characters
- *
- * \param[out] str Location to receive extracted characters.
- * \param[in] n Size of str.
- * \param[in] delim Delimiter
- *
- * Characters are extracted until extraction fails,
- * the next character equals \a delim (delim is extracted), or n-1
- * characters are extracted.
- *
- * The failbit is set if no characters are extracted or n-1 characters
- * are extracted. If end-of-file occurs the eofbit is set.
- *
- * \return always returns *this. A failure is indicated by the stream state.
- */
- istream& istream::getline(char *str, streamsize n, char delim) {
- FatPos_t pos;
- int c;
- m_gcount = 0;
- if (n > 0) str[0] = '\0';
- while (1) {
- c = getch(&pos);
- if (c < 0) {
- break;
- }
- if (c == delim) {
- m_gcount++;
- break;
- }
- if ((m_gcount + 1) >= n) {
- setpos(&pos);
- setstate(failbit);
- break;
- }
- str[m_gcount++] = c;
- str[m_gcount] = '\0';
- }
- if (m_gcount == 0) setstate(failbit);
- return *this;
- }
- //------------------------------------------------------------------------------
- bool istream::getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num) {
- int16_t c;
- int8_t any = 0;
- int8_t have_zero = 0;
- uint8_t neg;
- uint32_t val = 0;
- uint32_t cutoff;
- uint8_t cutlim;
- FatPos_t endPos;
- uint8_t f = flags() & basefield;
- uint8_t base = f == oct ? 8 : f != hex ? 10 : 16;
- getpos(&endPos);
- c = readSkip();
-
- neg = c == '-' ? 1 : 0;
- if (c == '-' || c == '+') {
- c = getch();
- }
-
- if (base == 16 && c == '0') { // TESTSUITE
- c = getch(&endPos);
- if (c == 'X' || c == 'x') {
- c = getch();
- // remember zero in case no hex digits follow x/X
- have_zero = 1;
- } else {
- any = 1;
- }
- }
- // set values for overflow test
- cutoff = neg ? negMax : posMax;
- cutlim = cutoff % base;
- cutoff /= base;
-
- while (1) {
- if (isdigit(c)) {
- c -= '0';
- } else if (isalpha(c)) {
- c -= isupper(c) ? 'A' - 10 : 'a' - 10;
- } else {
- break;
- }
- if (c >= base) {
- break;
- }
- if (val > cutoff || (val == cutoff && c > cutlim)) {
- // indicate overflow error
- any = -1;
- break;
- }
- val = val * base + c;
- c = getch(&endPos);
- any = 1;
- }
- setpos(&endPos);
- if (any > 0 || (have_zero && any >= 0)) {
- *num = neg ? -val : val;
- return true;
- }
- setstate(failbit);
- return false;
- }
- //------------------------------------------------------------------------------
- /**
- *
- */
- void istream::getStr(char *str) {
- FatPos_t pos;
- uint16_t i = 0;
- uint16_t m = width() ? width() - 1 : 0XFFFE;
- if (m != 0) {
- getpos(&pos);
- int c = readSkip();
-
- while (i < m) {
- if (c < 0) {
- break;
- }
- if (isspace(c)) {
- setpos(&pos);
- break;
- }
- str[i++] = c;
- c = getch(&pos);
- }
- }
- str[i] = '\0';
- if (i == 0) setstate(failbit);
- width(0);
- }
- //------------------------------------------------------------------------------
- /**
- * Extract characters and discard them.
- *
- * \param[in] n maximum number of characters to ignore.
- * \param[in] delim Delimiter.
- *
- * Characters are extracted until extraction fails, \a n characters
- * are extracted, or the next input character equals \a delim
- * (the delimiter is extracted). If end-of-file occurs the eofbit is set.
- *
- * Failures are indicated by the state of the stream.
- *
- * \return *this
- *
- */
- istream& istream::ignore(streamsize n, int delim) {
- int c;
- m_gcount = 0;
- while (m_gcount < n) {
- c = getch();
- if (c < 0) {
- break;
- }
- m_gcount++;
- if (c == delim) break;
- }
- return *this;
- }
- //------------------------------------------------------------------------------
- /**
- * Return the next available character without consuming it.
- *
- * \return The character if the stream state is good else -1;
- *
- */
- int istream::peek() {
- int16_t c;
- FatPos_t pos;
- m_gcount = 0;
- getpos(&pos);
- c = getch();
- if (c < 0) {
- if (!bad()) setstate(eofbit);
- } else {
- setpos(&pos);
- }
- return c;
- }
- //------------------------------------------------------------------------------
- int16_t istream::readSkip() {
- int16_t c;
- do {
- c = getch();
- } while (isspace(c) && (flags() & skipws));
- return c;
- }
- //------------------------------------------------------------------------------
- /** used to implement ws() */
- void istream::skipWhite() {
- int c;
- FatPos_t pos;
- do {
- c = getch(&pos);
- } while (isspace(c));
- setpos(&pos);
- }
|