Changeset 10270
- Timestamp:
- 03/30/11 15:41:11 (14 years ago)
- Location:
- trunk/FACT++/src
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/FACT++/src/Converter.cc
r10219 r10270 2 2 /** @class Converter 3 3 4 @brief A n interpreter to convert a command line into a command plus data memory4 @brief A compiler for the DIM data format string 5 5 6 6 The Converter class interprets arguments in a string accoring to the … … 21 21 22 22 \code 23 Converter c(cout, "I:1;F:2;I:2", "COMMAND 1 2.5 4.2 3 4"); 23 Converter c(cout, "I:1;F:2;I:2", ); 24 vector<char> v = c.GetVector("COMMAND 1 2.5 4.2 3 4"); 24 25 \endcode 25 26 … … 30 31 31 32 \code 32 Converter c(cout, "I:1;F:2;I:2", pointer, size); 33 Converter c(cout, "I:1;F:2;I:2"); 34 cout << c.GetString(pointer, size) << endl; 33 35 \endcode 34 36 37 Other conversion functions also exist. 38 39 A result of a conversion is valid if valid() returns true and either the 40 result of the conversion is empty and the format string was valid empty 41 or both contain contents. 42 43 The format parameter \b W(ord) is dedicated to this kind of conversion and 44 not understood by Dim. In addition there are \b O(ptions) which are like 45 Words but can be omitted. They should only be used at the end of the string. 46 \b B(ool) is also special. It evaluates true/false, yes/no, on/off, 1/0. 47 48 The non-DIM like format options can be switched on and off by using the 49 strict argument in the constructor. 50 51 */ 52 // ************************************************************************** 53 #include "Converter.h" 54 55 #include <iostream> 56 #include <iomanip> 57 #include <sstream> 58 59 #include <cctype> // std::tolower 60 #include <algorithm> // std::transform 61 62 #include <boost/regex.hpp> 63 64 #include "Readline.h" 65 #include "WindowLog.h" 66 67 using namespace std; 68 /* 35 69 In addition to converting the options from a string into binary format 36 70 or back all found values are also put into a vector of boost::any objects. … … 46 80 cout << c.Get<string>(4) << endl; // prints 'is a test' 47 81 \endcode 48 49 The format parameter \b W(ord) is dedicated to this kind of conversion and50 not understood by Dim. In addition there are \b O(ptions) which are like51 Words but can be omitted. They should only be used at the end of the string.52 \b B(ool) is also special. It evaluates true/false, yes/no, on/off, 1/0.53 54 Access with Converter::Get() is exception safe. Access with Converter::At()55 would throw an exception if the index is out of bounds or the conversion56 fails. (This is the prefered method if the type is well known, to easily57 detect programing faults)58 59 @remark60 Most probably we support more formats than dim does...61 62 82 */ 63 // ************************************************************************** 64 #include "Converter.h" 65 66 #include <iomanip> 67 #include <sstream> 68 69 #include <cctype> // std::tolower 70 #include <algorithm> // std::transform 71 72 #include <boost/regex.hpp> 73 74 #include "Readline.h" 75 #include "WindowLog.h" 76 77 using namespace std; 78 83 84 // -------------------------------------------------------------------------- 85 // 86 //! This function is supposed to remove all whitespaces from the format 87 //! string to allow easier regular expressions later. 88 //! 89 //! @param s 90 //! string to be cleaned 91 //! 92 //! @returns 93 //! string cleaned from whitespaces 94 // 95 std::string Converter::Clean(std::string s) 96 { 97 while (1) 98 { 99 const size_t pos = s.find_last_of(' '); 100 if (pos==string::npos) 101 break; 102 s.erase(pos, pos+1); 103 } 104 105 return s; 106 } 107 108 // -------------------------------------------------------------------------- 109 // 110 //! This is just a simplification. For the time being it is used to output 111 //! the interpreted contents to the logging stream. Its main purpose 112 //! is to add the contents of val in a binary representation to the 113 //! vector v 114 //! 115 //! @tparam 116 //! data type of the variable which should be added 117 //! 118 //! @param val 119 //! reference to the data 120 //! 121 //! @param v 122 //! vector<char> to which the binary copy should be added 123 //! 79 124 template <class T> 80 void Converter::EvalImp(int i, std::stringstream &line, std::vector<char> &v, const T &val) 81 { 82 if (!line) 83 wout << " arg[" << i << "]"; 84 else 85 wout << " (" << val << ")"; 86 87 vec.push_back(val); 125 void Converter::GetBinImp(std::vector<char> &v, const T &val) const 126 { 127 wout << " (" << val << ")"; 88 128 89 129 v.insert(v.end(), … … 92 132 } 93 133 94 95 // -------------------------------------------------------------------------- 96 // 97 //! Gets a value of the template type T from the stringstream and adds the 98 //! value as binary data to the end of the vector. If a value couldn't be 99 //! obtained it is set to 0. 100 //! 101 //! Adds the value to Converter::vec. 102 //! 103 //! @param i 104 //! The number of the processed argument (currently used for some debug 105 //! output when an argument is not available and artificially set to 0) 134 // -------------------------------------------------------------------------- 135 // 136 //! This is just a simplification. For the time being it is used to output 137 //! the interpreted contents to the logging stream. Its main purpose 138 //! is to add the contents of val as a boost::any object to the 139 //! vector v 140 //! 141 //! @tparam 142 //! data type of the variable which should be added 143 //! 144 //! @param val 145 //! reference to the data 146 //! 147 //! @param v 148 //! vector<boost::any> to which the value should be added 149 //! 150 template <class T> 151 void Converter::GetBinImp(std::vector<boost::any> &v, const T &val) const 152 { 153 wout << " (" << val << ")"; 154 155 v.push_back(val); 156 } 157 158 // -------------------------------------------------------------------------- 159 // 160 //! This is just a simplification. For the time being it is used to output 161 //! the interpreted contents to the logging stream. Its main purpose 162 //! is to add the contents of the provided string at the end of the vector v. 163 //! vector v 164 //! 165 //! @param val 166 //! reference to the string 167 //! 168 //! @param v 169 //! vector<char> to which the value should be added 170 //! 171 void Converter::GetBinString(std::vector<char> &v, const string &val) const 172 { 173 wout << " (" << val << ")"; 174 175 v.insert(v.end(), val.begin(), val.end()); 176 } 177 178 // -------------------------------------------------------------------------- 179 // 180 //! This is just a simplification. For the time being it is used to output 181 //! the interpreted contents to the logging stream. Its main purpose 182 //! is to add the contents of the provided string at the end of the vector v. 183 //! vector v 184 //! 185 //! @param val 186 //! reference to the string 187 //! 188 //! @param v 189 //! vector<boost::any> to which the value should be added 190 //! 191 void Converter::GetBinString(std::vector<boost::any> &v, const string &val) const 192 { 193 wout << " (" << val << ")"; 194 195 v.push_back(val); 196 } 197 198 // -------------------------------------------------------------------------- 199 // 200 //! Converts from the stringstream into the provided type. 106 201 //! 107 202 //! @param line 108 //! The stringstream from which the data should be read 109 //! 110 //! @param vec 111 //! The vector of bytes at which end the data is added in binary format 203 //! reference to the stringstream from which the data should be 204 //! interpreted 205 //! 206 //! @tparam 207 //! Type of the data to be returned 208 //! 209 //! @returns 210 //! The interpreted data 112 211 //! 113 212 template <class T> 114 void Converter::Eval(int i, std::stringstream &line, std::vector<char> &v) 213 T Converter::Get(std::stringstream &line) const 115 214 { 116 215 T val; 117 216 line >> val; 118 119 EvalImp(i, line, v, val); 120 } 121 122 // -------------------------------------------------------------------------- 123 // 124 //! This functions works similar the the template Eval but is dedicated to 125 //! bools. It evaluates yes/no, on/off, true/false and 1/0. 126 //! 127 //! Sets the failbit of the stream if the "value" is not known. 128 //! 129 //! Adds the value to Converter::vec. 217 return val; 218 } 219 220 // -------------------------------------------------------------------------- 221 // 222 //! Converts from the stringstream into bool. It allows to use lexical 223 //! boolean representations like yes/no, on/off, true/false and of 224 //! course 0/1. If the conversion fails the failbit is set. 130 225 //! 131 226 //! @param line 132 //! The stringstream from which the data should be read 133 //! 134 //! @param vec 135 //! The vector of bytes at which end the data is added in binary format 227 //! reference to the stringstream from which the data should be 228 //! interpreted 136 229 //! 137 230 //! @returns 138 //! The bool evaluated139 //! 140 void Converter::EvalBool(int i, std::stringstream &line, std::vector<char> &v) 231 //! The boolean. 0 in case of failure 232 //! 233 bool Converter::GetBool(std::stringstream &line) const 141 234 { 142 235 string buf; … … 145 238 146 239 if (buf=="yes" || buf=="true" || buf=="on" || buf=="1") 147 { 148 EvalImp(i, line, v, bool(true)); 149 return; 150 } 240 return true; 151 241 152 242 if (buf=="no" || buf=="false" || buf=="off" || buf=="0") 153 { 154 EvalImp(i, line, v, bool(false)); 155 return; 156 } 243 return false; 157 244 158 245 line.clear(ios::failbit); 159 } 160 161 void Converter::EvalString(int i, std::stringstream &line, std::vector<char> &v) 246 247 return false; 248 } 249 250 // -------------------------------------------------------------------------- 251 // 252 //! Converts from the stringstream into a string. Leading whitespaces are 253 //! skipped. Everything up to the next whitespace is returned. 254 //! strings can be encapsulated into escape characters ("). Note, that 255 //! they cannot be nested. 256 //! 257 //! @param line 258 //! reference to the stringstream from which the data should be 259 //! interpreted 260 //! 261 //! @returns 262 //! The string 263 //! 264 string Converter::GetString(std::stringstream &line) const 162 265 { 163 266 while (line.peek()==' ') … … 173 276 line >> buf; 174 277 175 EvalImp(i, line, v, buf); 176 } 177 178 // -------------------------------------------------------------------------- 179 // 180 //! Constructs a data block from the given string according to the given 181 //! format. (See also the class reference for more details). 182 //! 183 //! The data block is stored in a vector<char>. It's content can be 184 //! retrieved using the member functions Ptr() and Size(). Whether parsing 185 //! was successfull or not can be checked with GetRc(). 186 //! If parsing was not successfull, either the format contained something 187 //! odd, the conversion failed (e.g. 5.5 for an int) or the string contained 188 //! a wrong number of arguments. 278 return buf; 279 } 280 281 // -------------------------------------------------------------------------- 282 // 283 //! Converts from the stringstream into a string. Leading whitespaces are 284 //! skipped. Everything until the end-of-line is returned. A trailing 285 //! \0 is added. 286 //! 287 //! @param line 288 //! reference to the stringstream from which the data should be 289 //! interpreted 290 //! 291 //! @returns 292 //! The string 293 //! 294 string Converter::GetStringEol(stringstream &line) const 295 { 296 // Remove leading whitespaces 297 while (line.peek()==' ') 298 line.get(); 299 300 line >> noskipws; 301 302 const istream_iterator<char> eol; // end-of-line iterator 303 const string s(istream_iterator<char>(line), eol); 304 return s + '\0'; 305 } 306 307 // -------------------------------------------------------------------------- 308 // 309 //! Converts from a binary block into a string. The type of the expected 310 //! value is defined by the template parameter. 311 //! 312 //! @param ptr 313 //! A refrenece to the pointer of the binary representation to be 314 //! interpreted. The pointer is incremented by the sizeof the type. 315 //! 316 //! @tparam T 317 //! Expected type 318 //! 319 //! @returns 320 //! The string 321 //! 322 template<class T> 323 string Converter::GetString(const char* &ptr) const 324 { 325 const T &t = *reinterpret_cast<const T*>(ptr); 326 327 ostringstream stream; 328 stream << t; 329 ptr += sizeof(T); 330 331 return stream.str(); 332 } 333 334 // -------------------------------------------------------------------------- 335 // 336 //! Converts from a binary block into a hex representation. 337 //! 338 //! @param ptr 339 //! Pointer to the data block 340 //! 341 //! @param size 342 //! Size of the data block 343 //! 344 //! @returns 345 //! The string 346 //! 347 string Converter::GetHex(const void *dat, int size) 348 { 349 const char *ptr = reinterpret_cast<const char *>(dat); 350 351 ostringstream text; 352 353 text << hex; 354 355 for (int i=0; i<size; i++) 356 text << setw(2) << ptr[i] << " "; 357 358 return text.str(); 359 } 360 361 // -------------------------------------------------------------------------- 362 // 363 //! Convert the pointer using GetString into a string and add it (prefixed 364 //! by a whaitespace) to the given string. 365 //! 366 //! @param str 367 //! Reference to the string to which the ptr should be added 368 //! 369 //! @param ptr 370 //! Pointer to the binary representation. It will be incremented 371 //! according to the sze of the template argument 372 //! 373 //! @tparam T 374 //! Type as which the binary data should be interpreted 375 //! 376 template<class T> 377 void Converter::Add(string &str, const char* &ptr) const 378 { 379 str += ' ' + GetString<T>(ptr); 380 } 381 382 // -------------------------------------------------------------------------- 383 // 384 //! Convert the pointer into a boost::any object and add it to the 385 //! provided vector 386 //! 387 //! @param vec 388 //! Vector to which the boost::any object should be added 389 //! 390 //! @param ptr 391 //! Pointer to the binary representation. It will be incremented 392 //! according to the sze of the template argument 393 //! 394 //! @tparam T 395 //! Type as which the binary data should be interpreted 396 //! 397 template<class T> 398 void Converter::Add(vector<boost::any> &vec, const char* &ptr) const 399 { 400 vec.push_back(*reinterpret_cast<const T*>(ptr)); 401 ptr += sizeof(T); 402 } 403 404 // -------------------------------------------------------------------------- 405 // 406 //! Add the string pointed to by ptr to the given string. 407 //! 408 //! @param str 409 //! Reference to the string to which the ptr should be added 410 //! 411 //! @param ptr 412 //! Pointer to the binary representation. 413 //! 414 void Converter::AddString(string &str, const string &ptr) const 415 { 416 str += ' ' + ptr; 417 } 418 419 // -------------------------------------------------------------------------- 420 // 421 //! Add the string pointed to by ptr as boost::any to the provided vector 422 //! 423 //! @param vec 424 //! Vector to which the boost::any object should be added 425 //! 426 //! @param ptr 427 //! Pointer to the binary representation of the string. 428 //! 429 void Converter::AddString(vector<boost::any> &vec, const string &ptr) const 430 { 431 vec.push_back(ptr); 432 } 433 434 // -------------------------------------------------------------------------- 435 // 436 //! Compiles the format string into fList. See Compile() for more details. 189 437 //! 190 438 //! @param out 191 //! The ostream to which errors and debug messages should be printed.439 //! Output stream to which possible logging is redirected 192 440 //! 193 441 //! @param fmt 194 //! The format descriptor according to the dim definition 195 //! 196 //! @param str 197 //! The string which should be interpreted, e.g. "1 2 5.5 abcdef" 198 //! 199 Converter::Converter(std::ostream &out, const std::string &fmt, const std::string &str) 200 : rc(false), wout(out) 201 { 442 //! Format to be compiled. For details see class reference 443 //! 444 //! @param strict 445 //! Setting this to true allows non DIM options, whiel false 446 //! will restrict the possible format strings to the ones also 447 //! understood by DIM. 448 //! 449 Converter::Converter(std::ostream &out, const std::string &fmt, bool strict) 450 : wout(out), fFormat(Clean(fmt)), fList(Compile(out, fmt, strict)) 451 { 452 } 453 454 // -------------------------------------------------------------------------- 455 // 456 //! Compiles the format string into fList. 457 //! 458 //! Output by default is redirected to cout. 459 //! 460 //! @param fmt 461 //! Format to be compiled. For details see class reference 462 //! 463 //! @param strict 464 //! Setting this to true allows non DIM options, whiel false 465 //! will restrict the possible format strings to the ones also 466 //! understood by DIM. 467 //! 468 Converter::Converter(const std::string &fmt, bool strict) 469 : wout(cout), fFormat(Clean(fmt)), fList(Compile(fmt, strict)) 470 { 471 } 472 473 // -------------------------------------------------------------------------- 474 // 475 //! Converts the provided format string into a vector. 476 //! 477 //! @tparam T 478 //! Kind of data to be returned. This can either be boost::any objects 479 //! or a bnary data-block (char). 480 //! 481 //! @param fmt 482 //! Format to be compiled. For details see class reference 483 //! 484 //! @returns 485 //! A vector of the given template type containing the arguments. In 486 //! case of failure an empty vector is returned. 487 //! 488 template <class T> 489 vector<T> Converter::Get(const std::string &str) const 490 { 491 if (!valid()) 492 return vector<T>(); 493 202 494 // If the format is empty we are already done 203 if ( fmt.empty())204 { 205 if ( !str.empty())495 if (empty()) 496 { 497 if (str.empty()) 206 498 { 207 499 wout << endl; 208 wout << kRed << "Data string not empty as it ought to be!" << endl; 209 return; 500 return vector<T>(); 210 501 } 211 502 212 503 wout << endl; 213 rc = true; 214 return; 215 } 504 wout << kRed << "Data string not empty as it ought to be!" << endl; 505 return vector<T>(); 506 } 507 508 int arg = 0; 509 stringstream line(str); 510 511 vector<T> data; 512 513 for (Converter::FormatList::const_iterator i=fList.begin(); i<fList.end(); i++) 514 { 515 if (*i->first.first == typeid(string)) 516 { 517 GetBinString(data, GetStringEol(line)); 518 line.clear(ios::eofbit); 519 continue; 520 } 521 522 // Get as many items from the input line as requested 523 for (int j=0; j<i->second.first; j++) 524 { 525 cout << j << ": " << i->first.first->name() << endl; 526 switch (i->first.first->name()[0]) 527 { 528 case 'c': // Skip whitespaces when checking for characters 529 if (j>0) 530 line >> noskipws; 531 GetBinImp(data, Get<char>(line)); 532 line >> skipws; 533 break; 534 case 'b': GetBinImp(data, GetBool(line)); break; 535 case 's': GetBinImp(data, Get<short> (line)); break; 536 case 'i': GetBinImp(data, Get<int> (line)); break; 537 case 'l': GetBinImp(data, Get<long> (line)); break; 538 case 'f': GetBinImp(data, Get<float> (line)); break; 539 case 'd': GetBinImp(data, Get<double> (line)); break; 540 case 'x': GetBinImp(data, Get<long long>(line)); break; 541 case 'N': 542 GetBinString(data, GetString(line)); 543 if (*i->first.first == typeid(O)) 544 line.clear(ios::goodbit); 545 break; 546 default: 547 // This should never happen! 548 wout << endl << kRed << "Format '" << i->first.first->name() << " not supported!" << endl; 549 break; 550 } 551 552 arg++; 553 } 554 555 //wout << "{" << line.eof() << line.good() << line.fail() << "}"; 556 if (!line) 557 break; 558 } 559 560 wout << endl; 561 562 // Something wrong with the conversion (e.g. 5.5 for an int) 563 if (line.fail() && !line.eof()) 564 { 565 line.clear(); // This is necesasary to get a proper response from tellg() 566 wout << kRed << "Error converting argument at " << arg << " [fmt=" << fFormat << "]!" << endl; 567 wout << kRed << line.str() << endl; 568 wout << kRed << setw(int(line.tellg())) << " " << "^" << endl; 569 return vector<T>(); 570 } 571 572 // Not enough arguments, we have not reached the end 573 if (line.fail() && line.eof()) 574 { 575 line.clear(); 576 wout << kRed << "Not enough arguments [fmt=" << fFormat << "]!" << endl; 577 wout << kRed << line.str() << endl; 578 wout << kRed << setw(int(line.tellg())+1) << " " << "^" << endl; 579 return vector<T>(); 580 } 581 582 // Too many arguments, we have not reached the end 583 // Unfortunately, this can also mean that there is something 584 // wrong with the last argument 585 if (line.good() && !line.eof()) 586 { 587 wout << kRed << "More arguments available than expected [" << fFormat << "]!" << endl; 588 wout << kRed << line.str() << endl; 589 wout << kRed << setw(int(line.tellg())+1) << " " << "^" << endl; 590 return vector<T>(); 591 } 592 593 return data; 594 595 } 596 597 std::vector<boost::any> Converter::GetAny(const std::string &str) const 598 { 599 return Get<boost::any>(str); 600 } 601 602 std::vector<char> Converter::GetVector(const std::string &str) const 603 { 604 return Get<char>(str); 605 } 606 607 608 // -------------------------------------------------------------------------- 609 // 610 //! Converts the provided data block into a vector of boost::any or 611 //! a string. 612 //! 613 //! @tparam T 614 //! Kind of data to be returned. This can either be boost::any objects 615 //! or a string 616 //! 617 //! @returns 618 //! A vector of the given template type containing the arguments. In 619 //! case of failure an empty vector is returned. 620 //! 621 template<class T> 622 T Converter::Get(const void *dat, int size) const 623 { 624 if (!valid()) 625 return T(); 626 627 const char *ptr = reinterpret_cast<const char *>(dat); 628 629 T text; 630 for (Converter::FormatList::const_iterator i=fList.begin(); i<fList.end(); i++) 631 { 632 if (ptr-size>=dat) 633 { 634 wout << kRed << "Format description '" << fFormat << "' exceeds available data size (" << size << ")" << endl; 635 return T(); 636 } 637 638 if (*i->first.first == typeid(string)) 639 { 640 const string str(ptr); 641 AddString(text, str); 642 ptr += str.length()+1; 643 break; 644 } 645 646 // Get as many items from the input line as requested 647 for (int j=0; j<i->second.first; j++) 648 { 649 switch (i->first.first->name()[0]) 650 { 651 case 'b': Add<bool> (text, ptr); break; 652 case 'c': Add<char> (text, ptr); break; 653 case 's': Add<short> (text, ptr); break; 654 case 'i': Add<int> (text, ptr); break; 655 case 'l': Add<long> (text, ptr); break; 656 case 'f': Add<float> (text, ptr); break; 657 case 'd': Add<double> (text, ptr); break; 658 case 'x': Add<long long>(text, ptr); break; 659 case 'v': 660 // This should never happen! 661 wout << kRed << "Type 'void' not supported!" << endl; 662 return T(); 663 default: 664 // This should never happen! 665 wout << kRed << "TypeId '" << i->first.first->name() << "' not known!" << endl; 666 return T(); 667 } 668 } 669 } 670 671 if (ptr-size!=dat) 672 { 673 wout << kRed << "Data block size (" << size << ") doesn't fit format description '" << fFormat << "'" << endl; 674 return T(); 675 } 676 677 return text; 678 } 679 680 std::vector<boost::any> Converter::GetAny(const void *dat, int size) const 681 { 682 return Get<vector<boost::any>>(dat, size); 683 } 684 685 std::vector<char> Converter::GetVector(const void *dat, int size) const 686 { 687 const string ref = GetString(dat, size); 688 689 vector<char> data; 690 data.insert(data.begin(), ref.begin()+1, ref.end()); 691 data.push_back(0); 692 693 return data; 694 } 695 696 string Converter::GetString(const void *dat, int size) const 697 { 698 return Get<string>(dat, size).substr(1); 699 } 700 701 template<class T> 702 Converter::Type Converter::GetType() 703 { 704 Type t; 705 t.first = &typeid(T); 706 t.second = sizeof(T); 707 return t; 708 } 709 710 template<class T> 711 Converter::Type Converter::GetVoid() 712 { 713 Type t; 714 t.first = &typeid(T); 715 t.second = 0; 716 return t; 717 } 718 719 // -------------------------------------------------------------------------- 720 // 721 //! static function to compile a format string. 722 //! 723 //! @param out 724 //! Output stream to which possible logging is redirected 725 //! 726 //! @param fmt 727 //! Format to be compiled. For details see class reference 728 //! 729 //! @param strict 730 //! Setting this to true allows non DIM options, whiel false 731 //! will restrict the possible format strings to the ones also 732 //! understood by DIM. 733 //! 734 Converter::FormatList Converter::Compile(std::ostream &out, const std::string &fmt, bool strict) 735 { 736 ostringstream text; 216 737 217 738 // Access both, the data and the format through a stringstream 218 stringstream line(str);219 739 stringstream stream(fmt); 220 740 221 741 // For better performance we could use sregex 222 static const boost::regex expr("^[ ]*([OBWCSILFDX])[ ]*(:[ ]*([1-9]+[0-9]*))?[ ]*$"); 742 static const boost::regex expr1("^([CSILFDXBOW])(:([1-9]+[0-9]*))?$"); 743 static const boost::regex expr2("^([CSILFDX])(:([1-9]+[0-9]*))?$"); 744 745 FormatList list; 746 Format format; 223 747 224 748 // Tokenize the format 225 int arg = 0;226 749 string buffer; 227 750 while (getline(stream, buffer, ';')) 228 751 { 229 752 boost::smatch what; 230 if (!boost::regex_match(buffer, what, expr))753 if (!boost::regex_match(buffer, what, strict?expr2:expr1)) 231 754 { 232 wout << endl; 233 wout << kRed << "Wrong format string '" << buffer << "'!" << endl; 234 return; 755 out << kRed << "Wrong format string '" << buffer << "'!" << endl; 756 return FormatList(); 235 757 } 236 758 … … 238 760 const string n = what[3]; // counter 239 761 240 int cnt = atoi(n.c_str()); 762 const int cnt = atoi(n.c_str()); 763 764 // if the :N part was not given assume 1 765 format.second.first = cnt == 0 ? 1: cnt; 241 766 242 767 // Check if the format is just C (without a number) … … 244 769 if (t[0]=='C' && cnt==0) 245 770 { 246 // Remove leading whitespaces 247 while (line.peek()==' ') 248 line.get(); 249 250 line >> noskipws; 251 252 const istream_iterator<char> eol; // end-of-line iteartor 253 const string s(istream_iterator<char>(line), eol); 254 255 vec.push_back(s); 256 257 data.insert(data.end(), s.begin(), s.end()); 258 data.push_back(0); 259 260 line.clear(ios::eofbit); 261 262 continue; 263 } 264 265 // if the :N part was not given assume 1 266 if (cnt==0) 267 cnt=1; 268 269 // Get as many items from the input line as requested 270 for (int j=0; j<cnt; j++) 271 switch (t[0]) 272 { 273 case 'C': // Skip whitespaces when checking for characters 274 if (j>0) 275 line >> noskipws; 276 Eval<char>(arg++, line, data); 277 line >> skipws; 278 break; 279 case 'B': EvalBool (arg++, line, data); break; 280 case 'S': Eval<short> (arg++, line, data); break; 281 case 'I': Eval<int> (arg++, line, data); break; 282 case 'L': Eval<long> (arg++, line, data); break; 283 case 'F': Eval<float> (arg++, line, data); break; 284 case 'D': Eval<double> (arg++, line, data); break; 285 case 'X': Eval<long long>(arg++, line, data); break; 286 case 'W': EvalString (arg++, line, data); break; 287 case 'O': EvalString (arg++, line, data); line.clear(ios::goodbit); break; 288 default: 289 // This should never happen! 290 wout << endl << kRed << "Format '" << t[0] << " not known!" << endl; 291 break; 292 } 293 294 //wout << "{" << line.eof() << line.good() << line.fail() << "}"; 295 if (!line) 296 break; 297 } 298 //wout << "{" << line.eof() << line.good() << line.fail() << "}"; 299 300 wout << " [" << fmt << "]=" << data.size() << endl; 301 302 // Something wrong with the conversion (e.g. 5.5 for an int) 303 if (line.fail() && !line.eof()) 304 { 305 line.clear(); // This is necesasary to get a proper response from tellg() 306 wout << kRed << "Error converting argument at " << arg << " [fmt=" << fmt << "]!" << endl; 307 wout << kRed << str << endl; 308 wout << kRed << setw(int(line.tellg())) << " " << "^" << endl; 309 return; 310 } 311 312 // Not enough arguments, we have not reached the end 313 if (line.fail() && line.eof()) 314 { 315 line.clear(); 316 wout << kRed << "Not enough arguments [fmt=" << fmt << "]!" << endl; 317 wout << kRed << str << endl; 318 wout << kRed << setw(int(line.tellg())+1) << " " << "^" << endl; 319 return; 320 } 321 322 // Too many arguments, we have not reached the end 323 // Unfortunately, this can also mean that there is something 324 // wrong with the last argument 325 if (line.good() && !line.eof()) 326 { 327 wout << kRed << "More arguments available than expected [" << fmt << "]!" << endl; 328 wout << kRed << str << endl; 329 wout << kRed << setw(int(line.tellg())+1) << " " << "^" << endl; 330 return; 331 } 332 333 // Set return code to true (successfull) 334 rc = true; 335 } 336 337 // -------------------------------------------------------------------------- 338 // 339 //! Gets the value as a binary from the ptr and return it as a string. 340 //! The pointer is increased accordingly. 341 //! 342 //! Adds the value to Converter::vec. 343 //! 344 //! @param ptr 345 //! A reference to a pointer to the data which should be converted. 346 //! The pointer is increased according to the size of the data. 347 //! 348 //! @returns 349 //! The data converted into a string 350 //! 351 template<class T> 352 string Converter::Get(const char* &ptr) 353 { 354 const T &t = *reinterpret_cast<const T*>(ptr); 355 356 vec.push_back(t); 357 358 ostringstream stream; 359 stream << t; 360 ptr += sizeof(T); 361 362 return stream.str(); 363 } 364 365 // -------------------------------------------------------------------------- 366 // 367 //! Constructs a string from the given data block according to the specified 368 //! format. (See also the class reference for more details). 369 //! 370 //! The resulting string is stored in vector<char> and 0-terminated. 371 //! It can be accessed through Ptr(). 372 //! 373 //! If the conversion faild GetRc will return false. In this case the data 374 //! contents might not be well defined. 375 //! 376 //! If no format is given (size == 0) but the data size is finite (>0) 377 //! then the data is converted into a hex representation. 378 //! 379 //! @remark 380 //! In cases of failures the stored data might be inexisting and 381 //! Ptr() might return NULL. If you output NULL to our streams 382 //! they might not show any further output anymore. 383 //! 384 //! @param fmt 385 //! The format descriptor according to the dim definition 386 //! 387 //! @param out 388 //! The ostream to which errors and debug messages should be printed. 389 //! 390 //! @param dat 391 //! Pointer to the start of the binary data 392 //! 393 //! @param size 394 //! Size of the binary data region 395 //! 396 Converter::Converter(ostream &out, const string &fmt, const void *dat, int size) 397 : rc(false), wout(out) 398 { 399 const char *ptr = reinterpret_cast<const char *>(dat); 400 401 ostringstream text; 402 403 // Structure: print hex representation 404 if (fmt.size()==0) 405 { 406 if (size==0) 407 { 408 data.push_back(0); 409 rc = true; 410 return; 411 } 412 413 text << hex; 414 415 for (int i=0; i<size; i++) 416 text << setw(2) << ptr[i] << " "; 417 418 const string &ref = text.str(); 419 data.insert(data.begin(), ref.begin(), ref.end()); 420 data.push_back(0); 421 return; 422 } 423 424 // Access both, the data and the format through a stringstream 425 stringstream stream(fmt); 426 427 // For better performance we could use sregex 428 static const boost::regex expr("^[ ]*([CSILFDX])[ ]*(:[ ]*([1-9]+[0-9]*))?[ ]*$"); 429 430 // Tokenize the format 431 string buffer; 432 while (getline(stream, buffer, ';')) 433 { 434 if (ptr-size>=dat) 435 { 436 wout << kRed << "Format description '" << fmt << "' exceeds available data size (" << size << ")" << endl; 437 return; 438 } 439 440 boost::smatch what; 441 if (!boost::regex_match(buffer, what, expr)) 442 { 443 wout << kRed << "Wrong format string '" << buffer << "'!" << endl; 444 return; 445 } 446 447 const string t = what[1]; // type id 448 const string n = what[3]; // counter 449 450 int cnt = atoi(n.c_str()); 451 452 // Check if the format is just C (without a number) 453 // That would mean that it is a \0 terminated string 454 if (t[0]=='C' && cnt==0) 455 { 456 const string str(ptr); 457 text << ' ' << str; 458 ptr += str.length()+1; 459 460 vec.push_back(str); 461 771 format.first = GetType<string>(); 772 list.push_back(format); 773 format.second.second = 0; // end position not known 462 774 break; 463 775 } 464 776 465 // if the :N part was not given assume 1466 if (cnt==0)467 cnt=1;468 469 777 // Get as many items from the input line as requested 470 for (int j=0; j<cnt; j++)778 switch (t[0]) 471 779 { 472 text << ' '; 473 474 switch (t[0]) 475 { 476 case 'C': text << Get<char> (ptr); break; 477 case 'S': text << Get<short> (ptr); break; 478 case 'I': text << Get<int> (ptr); break; 479 case 'L': text << Get<long> (ptr); break; 480 case 'F': text << Get<float> (ptr); break; 481 case 'D': text << Get<double> (ptr); break; 482 case 'X': text << Get<long long>(ptr); break; 483 default: 484 // This should never happen! 485 wout << kRed << "Format '" << t[0] << " not known!" << endl; 486 return; 487 } 780 case 'B': format.first = GetType<bool>(); break; 781 case 'C': format.first = GetType<char>(); break; 782 case 'S': format.first = GetType<short>(); break; 783 case 'I': format.first = GetType<int>(); break; 784 case 'L': format.first = GetType<long>(); break; 785 case 'F': format.first = GetType<float>(); break; 786 case 'D': format.first = GetType<double>(); break; 787 case 'X': format.first = GetType<long long>(); break; 788 case 'O': format.first = GetVoid<O>(); break; 789 case 'W': format.first = GetVoid<W>(); break; 790 default: 791 // This should never happen! 792 out << kRed << "Format '" << t[0] << " not known!" << endl; 793 return list; 488 794 } 489 } 490 491 if (ptr-size!=dat) 492 { 493 wout << kRed << "Data block size (" << size << ") doesn't fit format description '" << fmt << "'" << endl; 494 return; 495 } 496 497 rc = true; 498 499 const string &ref = text.str(); 500 data.insert(data.begin(), ref.begin()+1, ref.end()); 501 data.push_back(0); 502 } 503 504 795 796 list.push_back(format); 797 format.second.second += format.first.second * format.second.first; 798 } 799 800 format.first = GetVoid<void>(); 801 format.second.first = 0; 802 803 list.push_back(format); 804 805 return list; 806 } 807 808 // -------------------------------------------------------------------------- 809 // 810 //! Same as Compile(ostream&,string&,bool) but cout is used as the default 811 //! output stream. 812 //! 813 //! 814 Converter::FormatList Converter::Compile(const std::string &fmt, bool strict) 815 { 816 return Compile(cout, fmt, strict); 817 } 505 818 506 819 vector<string> Converter::Regex(const string &expr, const string &line) -
trunk/FACT++/src/Converter.h
r10219 r10270 9 9 class Converter 10 10 { 11 public: 12 typedef std::pair<const std::type_info *, int> Type; 13 typedef std::pair<int, int> Offset; 14 typedef std::pair<Type, Offset> Format; 15 typedef std::vector<Format> FormatList; 16 17 struct O { }; 18 struct W { }; 19 20 static std::string Clean(std::string s); 21 11 22 private: 12 bool rc; /// Flag for the success of the conversion 13 std::ostream &wout; /// ostream to which output is redirected 14 std::vector<char> data; /// data storage 15 std::vector<boost::any> vec; /// storage for typed data 23 std::ostream &wout; /// ostream to which output is redirected 24 25 const std::string fFormat; /// Original format string 26 const FormatList fList; /// Compiled format description 27 28 template <class T> 29 T Get(std::stringstream &line) const; 30 31 bool GetBool(std::stringstream &line) const; 32 std::string GetString(std::stringstream &line) const; 33 std::string GetStringEol(std::stringstream &line) const; 16 34 17 35 template<class T> 18 void EvalImp(int i, std::stringstream &line, std::vector<char> &v, const T &val);36 void GetBinImp(std::vector<char> &v, const T &val) const; 19 37 template<class T> 20 void Eval(int i, std::stringstream &line, std::vector<char> &v); 21 void EvalBool(int i, std::stringstream &line, std::vector<char> &v); 22 void EvalString(int i, std::stringstream &line, std::vector<char> &v); 38 void GetBinImp(std::vector<boost::any> &v, const T &val) const; 39 40 void GetBinString(std::vector<char> &v, const std::string &val) const; 41 void GetBinString(std::vector<boost::any> &v, const std::string &val) const; 23 42 24 43 template<class T> 25 std::string Get(const char *&data); 44 std::string GetString(const char *&data) const; 45 46 template<class T> 47 static Type GetType(); 48 template<class T> 49 static Type GetVoid(); 50 51 template <class T> 52 std::vector<T> Get(const std::string &str) const; 53 template <class T> 54 T Get(const void *d, int size) const; 55 56 57 58 template<class T> 59 void Add(std::string &str, const char* &ptr) const; 60 void AddString(std::string &str, const std::string &ptr) const; 61 template<class T> 62 void Add(std::vector<boost::any> &vec, const char* &ptr) const; 63 void AddString(std::vector<boost::any> &vec, const std::string &ptr) const; 64 26 65 27 66 public: 28 Converter(std::ostream &out, const std::string &fmt, const std::string &str);29 Converter( std::ostream &out, const std::string &fmt, const void *d, int size);67 Converter(std::ostream &out, const std::string &fmt, bool strict=true); 68 Converter(const std::string &fmt, bool strict=true); 30 69 31 /// Returns whether the conversion was successfull32 bool GetRc() const { return rc; }70 /// @returns whether the interpreted format was valid but empty ("") 71 bool empty() const { return fList.size()==1 && fList.back().first.second==0; } 33 72 34 /// const Pointer to the data memory 35 const char *Ptr() const { return &*data.begin(); } 36 /// non-const Pointer to the data memory (for convinience using Dim) 37 char *Ptr() { return &*data.begin(); } 73 /// @returns whether the compilation was successfull 74 bool valid() const { return !fList.empty() && fList.back().first.second==0; } 38 75 39 /// Return the size of the data memory40 int Size() const { return data.size(); }76 /// @returns true if the compilation failed 77 bool operator!() const { return !valid(); } 41 78 42 /// Return the data memory converted into a string (not necessarily \0-terminated) 43 const std::string Str() const { return std::string(&*data.begin(), data.size()); } 79 const FormatList &GetList() const { return fList; } 44 80 81 static FormatList Compile(std::ostream &out, const std::string &fmt, bool strict=false); 82 static FormatList Compile(const std::string &fmt, bool strict=false); 45 83 84 std::string GetString(const void *d, int size) const; 85 std::vector<char> GetVector(const void *d, int size) const; 86 std::vector<boost::any> GetAny(const void *d, int size) const; 87 88 std::vector<boost::any> GetAny(const std::string &str) const; 89 std::vector<char> GetVector(const std::string &str) const; 90 91 static std::string GetHex(const void *d, int size); 92 93 /* 46 94 // Returns the number of entries in Converter:vec 47 95 int N() const { return vec.size(); } … … 58 106 template <class T> 59 107 T At(int i) const { return boost::any_cast<T>(vec[i]); } 60 108 */ 61 109 62 110 static std::vector<std::string> Regex(const std::string &expr, const std::string &line);
Note:
See TracChangeset
for help on using the changeset viewer.