$search
00001 00011 /***************************************************************************** 00012 ** Ifdefs 00013 *****************************************************************************/ 00014 00015 #ifndef ECL_STREAMS_INPUT_TEXT_STREAM_HPP_ 00016 #define ECL_STREAMS_INPUT_TEXT_STREAM_HPP_ 00017 00018 /***************************************************************************** 00019 ** Includes 00020 *****************************************************************************/ 00021 00022 #include <iostream> 00023 #include <limits> 00024 #include <string> 00025 #include <ecl/config/macros.hpp> 00026 #include <ecl/config/portable_types.hpp> 00027 #include <ecl/exceptions/standard_exception.hpp> 00028 #include <ecl/concepts/devices.hpp> 00029 #include <ecl/type_traits/numeric_limits.hpp> 00030 #include "base_text_stream.hpp" 00031 00032 /***************************************************************************** 00033 ** Namespaces 00034 *****************************************************************************/ 00035 00036 namespace ecl { 00037 namespace interfaces { 00038 00039 /***************************************************************************** 00040 ** Interface [InputTextStream] 00041 *****************************************************************************/ 00042 00055 template <typename Device, bool InputDevice = true > 00056 class ECL_PUBLIC InputTextStream { 00057 }; 00058 00085 template <typename Device> 00086 class ECL_PUBLIC InputTextStream<Device,true> : public virtual BaseTextStream<Device> { 00087 public: 00088 /********************* 00089 ** Constructors 00090 **********************/ 00091 InputTextStream(); 00092 virtual ~InputTextStream() {} 00093 00094 /********************* 00095 ** Streaming Operators 00096 **********************/ 00097 InputTextStream<Device>& operator >> ( char &c ) ecl_assert_throw_decl(ecl::StandardException); 00098 InputTextStream<Device>& operator >> ( std::string &s ) ecl_assert_throw_decl(ecl::StandardException); 00099 InputTextStream<Device>& operator >> ( short &i ) ecl_assert_throw_decl(ecl::StandardException); 00100 InputTextStream<Device>& operator >> ( int &i ) ecl_assert_throw_decl(ecl::StandardException); 00101 InputTextStream<Device>& operator >> ( long &i ) ecl_assert_throw_decl(ecl::StandardException); 00102 InputTextStream<Device>& operator >> ( unsigned char &c ) ecl_assert_throw_decl(ecl::StandardException); 00103 InputTextStream<Device>& operator >> ( unsigned short &i ) ecl_assert_throw_decl(ecl::StandardException); 00104 InputTextStream<Device>& operator >> ( unsigned int &i ) ecl_assert_throw_decl(ecl::StandardException); 00105 InputTextStream<Device>& operator >> ( unsigned long &i ) ecl_assert_throw_decl(ecl::StandardException); 00106 InputTextStream<Device>& operator >> ( float &f ) ecl_assert_throw_decl(ecl::StandardException); 00107 InputTextStream<Device>& operator >> ( double &d ) ecl_assert_throw_decl(ecl::StandardException); 00108 InputTextStream<Device>& operator >> ( long long &i ) ecl_assert_throw_decl(ecl::StandardException); 00109 InputTextStream<Device>& operator >> ( unsigned long long &i ) ecl_assert_throw_decl(ecl::StandardException); 00110 InputTextStream<Device>& operator >> ( bool &b ) ecl_assert_throw_decl(ecl::StandardException); 00111 00112 /********************* 00113 ** Non-Streaming API 00114 **********************/ 00115 void enableRawCharReads(); 00116 void disableRawCharReads(); 00117 00118 private: 00119 bool raw_char_reads; 00120 00121 /********************* 00122 ** Private Parsers 00123 **********************/ 00124 bool skipLeadingWhiteSpace(char &c); 00125 template <typename Number> 00126 bool getIntegerFromStream(Number &i); 00127 template <typename Number> 00128 bool parseHexInteger(Number &i); 00129 template <typename Number> 00130 bool getFloatFromStream(Number &f); 00131 }; 00132 00133 /***************************************************************************** 00134 ** Implementation [InputTextStream] 00135 *****************************************************************************/ 00146 template <typename Device> 00147 InputTextStream<Device,true>::InputTextStream() : raw_char_reads(false) { 00148 ecl_compile_time_concept_check(ecl::InputCharDeviceConcept<Device>); 00149 } 00150 00151 /***************************************************************************** 00152 ** Implementation [InputTextStream][Streaming Operators] 00153 *****************************************************************************/ 00164 template <typename Device> 00165 InputTextStream<Device> & InputTextStream<Device,true>::operator >> ( char &c ) ecl_assert_throw_decl(ecl::StandardException) { 00166 00167 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00168 00169 if ( !raw_char_reads ) { 00170 if( skipLeadingWhiteSpace(c) ) { 00171 this->error = NoError; 00172 } else { 00173 this->error = ReadError; 00174 } 00175 } else { 00176 if ( this->io_device.read(c) == 1 ) { 00177 this->error = NoError; 00178 } else { 00179 this->error = ReadError; 00180 } 00181 } 00182 return *this; 00183 } 00184 00196 template <typename Device> 00197 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( std::string &s ) ecl_assert_throw_decl(ecl::StandardException) { 00198 00199 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00200 00201 char c; 00202 if ( skipLeadingWhiteSpace(c) ) { 00203 s.clear(); 00204 do { 00205 s.push_back(c); 00206 if( this->io_device.read(c) < 1 ) { 00207 this->error = ReadError; 00208 break; 00209 } 00210 } while ( ( c != ' ' ) && ( c != '\n' ) ); 00211 this->error = NoError; 00212 } else { 00213 this->error = ReadError; 00214 } 00215 00216 // Original method - reads a whole line (must be terminated by a \n) 00217 // static char buffer[80]; 00218 // this->io_device.read(&buffer[0],80); 00219 // s.assign(buffer); 00220 return *this; 00221 } 00222 00231 template <typename Device> 00232 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( short &i ) ecl_assert_throw_decl(ecl::StandardException) { 00233 00234 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00235 00236 if ( getIntegerFromStream(i) ) { 00237 this->error = NoError; 00238 } // Real errors are handled internally in getIntegerFromStreams 00239 00240 return *this; 00241 } 00242 00251 template <typename Device> 00252 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( int &i ) ecl_assert_throw_decl(ecl::StandardException) { 00253 00254 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00255 if ( getIntegerFromStream(i) ) { 00256 this->error = NoError; 00257 } // Real errors are handled internally in getIntegerFromStreams 00258 return *this; 00259 } 00260 00269 template <typename Device> 00270 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( long &i ) ecl_assert_throw_decl(ecl::StandardException) { 00271 00272 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00273 if ( getIntegerFromStream(i) ) { 00274 this->error = NoError; 00275 } // Real errors are handled internally in getIntegerFromStreams 00276 return *this; 00277 } 00286 template <typename Device> 00287 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( long long &i ) ecl_assert_throw_decl(ecl::StandardException) { 00288 00289 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00290 if ( getIntegerFromStream(i) ) { 00291 this->error = NoError; 00292 } // Real errors are handled internally in getIntegerFromStreams 00293 return *this; 00294 } 00305 template <typename Device> 00306 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned char &uc ) ecl_assert_throw_decl(ecl::StandardException) { 00307 00308 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00309 if ( getIntegerFromStream(uc) ) { 00310 this->error = NoError; 00311 } // Real errors are handled internally in getIntegerFromStreams 00312 return *this; 00313 } 00314 00323 template <typename Device> 00324 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned short &i ) ecl_assert_throw_decl(ecl::StandardException) { 00325 00326 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00327 if ( getIntegerFromStream(i) ) { 00328 this->error = NoError; 00329 } // Real errors are handled internally in getIntegerFromStreams 00330 return *this; 00331 } 00332 00341 template <typename Device> 00342 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned int &i ) ecl_assert_throw_decl(ecl::StandardException) { 00343 00344 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00345 if ( getIntegerFromStream(i) ) { 00346 this->error = NoError; 00347 } // Real errors are handled internally in getIntegerFromStreams 00348 return *this; 00349 } 00350 00359 template <typename Device> 00360 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned long &i ) ecl_assert_throw_decl(ecl::StandardException) { 00361 00362 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00363 if ( getIntegerFromStream(i) ) { 00364 this->error = NoError; 00365 } // Real errors are handled internally in getIntegerFromStreams 00366 return *this; 00367 } 00368 00377 template <typename Device> 00378 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned long long &i ) ecl_assert_throw_decl(ecl::StandardException) { 00379 00380 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00381 if ( getIntegerFromStream(i) ) { 00382 this->error = NoError; 00383 } // Real errors are handled internally in getIntegerFromStreams 00384 return *this; 00385 } 00386 00387 00396 template <typename Device> 00397 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( float &f ) ecl_assert_throw_decl(ecl::StandardException) { 00398 00399 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00400 if ( getFloatFromStream(f) ) { 00401 this->error = NoError; 00402 } // Real errors are handled internally in getFloatFromStreams 00403 return *this; 00404 } 00405 00414 template <typename Device> 00415 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( double &d ) ecl_assert_throw_decl(ecl::StandardException) { 00416 00417 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00418 if ( getFloatFromStream(d) ) { 00419 this->error = NoError; 00420 } // Real errors are handled internally in getFloatFromStreams 00421 return *this; 00422 } 00423 00434 template <typename Device> 00435 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( bool &b ) ecl_assert_throw_decl(ecl::StandardException) 00436 { 00437 ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open.")); 00438 std::string s; 00439 *this >> s; 00440 00441 if ( this->fail() ) { // string could not be read 00442 return *this; // error already set 00443 } 00444 00445 if ( ( s == "true" ) || ( s == "TRUE" ) || ( s == "True" ) ) { 00446 b = true; 00447 this->error = NoError; 00448 } else if ( ( s == "false" ) || ( s == "FALSE" ) || ( s == "False" ) ) { 00449 b = false; 00450 this->error = NoError; 00451 } else { 00452 this->error = ConversionError; 00453 } 00454 return *this; 00455 } 00456 00457 /***************************************************************************** 00458 ** Implementation [InputTextStream][Non-Streaming Interface] 00459 *****************************************************************************/ 00460 00473 template <typename Device> 00474 void InputTextStream<Device,true>::enableRawCharReads() { raw_char_reads = true; } 00475 00484 template <typename Device> 00485 void InputTextStream<Device,true>::disableRawCharReads() { raw_char_reads = false; } 00486 00487 00488 /***************************************************************************** 00489 ** Implementation [InputTextStream][Private Parsers] 00490 *****************************************************************************/ 00491 00501 template <typename Device> 00502 bool InputTextStream<Device,true>::skipLeadingWhiteSpace(char &c) 00503 { 00504 do { 00505 if( this->io_device.read(c) < 1 ) { // Fail if either there is a read error OR there is nothing in the device. 00506 this->error = ReadError; 00507 return false; 00508 } 00509 } while ( ( c == ' ' ) || ( c == '\n' ) ); 00510 return true; 00511 } 00512 00517 template <typename Device> 00518 template <typename Number> 00519 bool InputTextStream<Device,true>::parseHexInteger(Number &i) 00520 { 00521 char c; 00522 static int digits[25]; 00523 static const short ceiling = numeric_limits<short>::maximum/10; 00524 00525 i = 0; 00526 int j = 0; 00527 while ( j < 25 ) { 00528 long n = this->io_device.read(c); 00529 if ( n < 0 ) { 00530 this->error = ReadError; 00531 return false; 00532 } else if ( n == 0 ) { 00533 break; // nothing more to read. 00534 } 00535 if ( ( c >= '0' ) && ( c <= '9') ) { 00536 digits[j] = c - '0'; 00537 } else if ( ( c >= 'a' ) && ( c <= 'f') ) { 00538 digits[j] = 10 + c - 'a'; 00539 } else if ( ( c >= 'A' ) && ( c <= 'F') ) { 00540 digits[j] = 10 + c - 'A'; 00541 } else { 00542 break; // No more valid characters to read. 00543 } 00544 ++j; 00545 } 00546 if ( j == 0 ) { 00547 this->error = ReadError; 00548 return false; 00549 } 00550 00551 short number = 0; 00552 for ( int k = 0; k < j; ++k ) { 00553 if ( number < ceiling ) { 00554 number = 16*number + (digits[k]); 00555 } else { 00556 this->error = OutOfRangeError; 00557 return false; 00558 } 00559 } 00560 i = number; 00561 return true; 00562 } 00563 00569 template <typename Device> 00570 template <typename Number> 00571 bool InputTextStream<Device,true>::getIntegerFromStream(Number &i) { 00572 00573 static char digits[25]; // 20 is the maximum needed on a 64 bit system for a long type 00574 static const Number ceiling = ecl::numeric_limits<Number>::maximum/10; 00575 char c = ' '; 00576 Number sign_multiplier = 1; 00577 Number number; 00578 00579 if ( !skipLeadingWhiteSpace(c) ) { return false; } 00580 00581 if ( c == '-' ) { // Negative 00582 if ( std::numeric_limits<Number>::min() != 0 ) { 00583 sign_multiplier = -1; 00584 if ( this->io_device.read(c) < 1 ) { 00585 this->error = ReadError; 00586 return false; 00587 } 00588 } // else do nothing and continue, an error will be found at the next step. 00589 } else if ( c == '+' ) { // Positive 00590 if ( this->io_device.read(c) < 1 ) { 00591 this->error = ReadError; 00592 return false; 00593 } 00594 } else if ( c == '0' ) { 00595 long n = this->io_device.read(c); 00596 if ( ( n == 0 ) || ( c == ' ' ) || ( c == '\n' ) ) { // It's just a single zero. 00597 i = 0; 00598 return true; 00599 } else if ( n < 0 ) { 00600 this->error = ReadError; 00601 return false; 00602 } else if ( c == 'x' ) { 00603 return parseHexInteger(i); 00604 } else { 00605 // its a regular integer, just continue 00606 } 00607 } else if ( c == 'x' ) { 00608 return parseHexInteger(i); 00609 } 00610 00611 /********************* 00612 ** Parse reg. integer 00613 **********************/ 00614 int j = 0; 00615 while ( ( c >= '0' ) && ( c <= '9') && ( j < 25 ) ) { 00616 digits[j] = c; 00617 j++; 00618 long n = this->io_device.read(c); 00619 if ( n < 0 ) { 00620 this->error = ReadError; 00621 return false; 00622 } else if ( n == 0 ) { 00623 break; 00624 } else { // n > 1 00625 } 00626 } 00627 if ( j == 0 ) { 00628 this->error = ConversionError; 00629 return false; 00630 } 00631 number = 0; 00632 for ( int k = 0; k < j; ++k ) 00633 { 00634 if ( number < ceiling ) 00635 { 00636 number = 10*number + (digits[k] - '0'); 00637 } else { 00638 this->error = OutOfRangeError; 00639 return false; 00640 } 00641 } 00642 i = sign_multiplier*number; 00643 00644 return true; 00645 } 00646 00647 template <typename Device> 00648 template <typename Number> 00649 bool InputTextStream<Device,true>::getFloatFromStream(Number &f) { 00650 static const int bufferSize = 25; 00651 static char digits[bufferSize]; // 20 is the maximum needed on a 64 bit system for a long type 00652 char c = ' '; 00653 int integral_length = 0; 00654 int decimal_length = 0; 00655 Number sign_multiplier = 1; 00656 Number number; 00657 00658 if ( !skipLeadingWhiteSpace(c) ) { return false; } 00659 00660 if ( c == '-' ) { 00661 sign_multiplier = -1; 00662 if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; } 00663 } else if ( c == '+' ) { 00664 if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; } 00665 } 00666 number = 0; 00667 /****************************************** 00668 ** Integral part 00669 *******************************************/ 00670 while ( ( c >= '0' ) && ( c <= '9') && ( integral_length < bufferSize ) ) { 00671 digits[integral_length] = c; 00672 long n = this->io_device.read(c); 00673 if ( n < 0 ) { 00674 this->error = ReadError; return false; 00675 } else if ( n == 0 ) { 00676 break; 00677 } else { // n > 1 00678 integral_length++; 00679 } 00680 } 00681 for ( int k = 0; k < integral_length; ++k ) { 00682 number = 10*number + (digits[k] - '0'); 00683 } 00684 00685 if ( c == '.' ) { 00686 float frac_multiplier = 1; 00687 if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; } 00688 /****************************************** 00689 ** Decimal part 00690 *******************************************/ 00691 while ( ( c >= '0' ) && ( c <= '9') && ( decimal_length < bufferSize ) ) { 00692 digits[decimal_length] = c; 00693 long n = this->io_device.read(c); 00694 if ( n < 0 ) { 00695 this->error = ReadError; return false; 00696 } else if ( n == 0 ) { 00697 break; 00698 } else { // n > 1 00699 decimal_length++; 00700 } 00701 } 00702 for ( int k = 0; k < decimal_length; ++k ) { 00703 frac_multiplier *= 0.1f; 00704 number = number + frac_multiplier*(digits[k] - '0'); 00705 } 00706 } 00707 00708 if ( (integral_length+decimal_length) == 0 ) { 00709 this->error = ConversionError; 00710 return false; 00711 } 00712 00713 f = sign_multiplier*number; 00714 00715 return true; 00716 } 00717 00718 } // namespace interfaces 00719 } // namespace ecl 00720 00721 #endif /* ECL_STREAMS_INPUT_TEXT_STREAM_HPP_ */