1 //============================================================================== 2 // 3 // This file is part of GPSTk, the GPS Toolkit. 4 // 5 // The GPSTk is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published 7 // by the Free Software Foundation; either version 3.0 of the License, or 8 // any later version. 9 // 10 // The GPSTk is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with GPSTk; if not, write to the Free Software Foundation, 17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 18 // 19 // This software was developed by Applied Research Laboratories at the 20 // University of Texas at Austin. 21 // Copyright 2004-2020, The Board of Regents of The University of Texas System 22 // 23 //============================================================================== 24 25 //============================================================================== 26 // 27 // This software was developed by Applied Research Laboratories at the 28 // University of Texas at Austin, under contract to an agency or agencies 29 // within the U.S. Department of Defense. The U.S. Government retains all 30 // rights to use, duplicate, distribute, disclose, or release this software. 31 // 32 // Pursuant to DoD Directive 523024 33 // 34 // DISTRIBUTION STATEMENT A: This software has been approved for public 35 // release, distribution is unlimited. 36 // 37 //============================================================================== 38 39 /** 40 * @file StringUtils.hpp 41 * StringUtils namespace and GPSTK string utility functions 42 */ 43 44 #ifndef GPSTK_STRINGUTILS_HPP 45 #define GPSTK_STRINGUTILS_HPP 46 47 #include <string> 48 #include <sstream> 49 #include <iomanip> 50 #include <iostream> 51 #include <list> 52 #include <vector> 53 #include <cstdio> /// @todo Get rid of the stdio.h dependency if possible. 54 #include <cctype> 55 #include <limits> 56 57 #ifdef _WIN32 58 #if _MSC_VER < 1700 59 // For lower version of visual studio 2012 use gnu regex 60 #include <regex.h> 61 #pragma comment(lib, "regex.lib") 62 #else 63 // visual studio 2012 support c++ 0x, and we use std::regex 64 #include <regex> 65 #endif 66 #else 67 // TODO: we should use std::regex for upper than g++ 4.6 68 #include <regex.h> 69 #endif 70 71 #include "Exception.hpp" 72 #include "HexDumpDataConfig.hpp" 73 74 namespace gpstk 75 { 76 /** @defgroup stringutilsgroup Text String Manipulation Tools 77 * @copydoc gpstk::StringUtils 78 */ 79 80 /** 81 * Stuff to make the C++ string class a little easier to use. 82 * 83 * All functions here will throw 84 * gpstk::StringUtils::StringException on an error. Any 85 * std::exception is converted to a 86 * gpstk::StringUtils::StringException so that's the only 87 * exception a user of this class needs to catch. 88 * 89 * For any function that modifies a string, make sure there is a 90 * non-const (std::string&) version and a const (const 91 * std::string&) version. The convention for writing the 92 * functions is the non-const version fully implements the 93 * function and the const version calls the non-const version. 94 */ 95 namespace StringUtils 96 { 97 // Most of the functionality here is inlined since they are 98 // fairly small functions. 99 100 /// @ingroup stringutilsgroup 101 //@{ 102 103 /// This is thrown instread of a std::exception when a 104 /// gpstk::StringUtils function fails. 105 /// @ingroup exceptiongroup 106 NEW_EXCEPTION_CLASS(StringException, Exception); 107 108 /// Leading character for floatFormat(), after any whitespace or sign. 109 enum class FFLead 110 { 111 Zero, ///< Start with zero, e.g. 0.12345 112 Decimal, ///< Start with decimal, e.g. .12345 113 NonZero ///< Start with the first non-zero digit, e.g. 1.2345 114 }; 115 116 /// How to handle sign in floatFormat() 117 enum class FFSign 118 { 119 NegOnly, ///< Prefix output with a minus sign (neg) or nothing (pos) 120 NegSpace, ///< Prefix output with a minus sign (neg) or space (pos) 121 NegPos ///< Prefix output with a minus sign (neg) or plus sign (pos) 122 }; 123 124 /// Alignment of data for floatFormat() 125 enum class FFAlign 126 { 127 Left, ///< Formatted output will be left-aligned. 128 Right ///< Formatted output will be right-aligned. 129 }; 130 131 /** 132 * Perform a formatted hex-dump of the (potentially) binary 133 * data to the given stream. 134 * 135 * @note argument order reversed from earlier implementations 136 * to avoid ambiguity of prototypes. 137 * 138 * @param[in] data data to hex-dump. 139 * @param[in,out] s stream to dump data to. 140 * @param[in] cfg formatting configuration. 141 */ 142 void hexDumpData(const std::string& data, 143 std::ostream& s, 144 const HexDumpDataConfig& cfg = HexDumpDataConfig()); 145 146 /** 147 * Perform a formatted hex-dump of the (potentially) binary 148 * data to the given stream. 149 * 150 * @deprecated Set cfg.prefix and use the 3-parameter 151 * function instead. 152 * 153 * @param s stream to dump data to. 154 * @param data data to hex-dump. 155 * @param indent indents the string by that many spaces. 156 * @param cfg formatting configuration. 157 */ 158 inline void hexDumpData(std::ostream& s, 159 const std::string& data, 160 unsigned indent = 0, 161 const HexDumpDataConfig& cfg = HexDumpDataConfig()); 162 163 /** 164 * Perform a formatted hex-dump of the (potentially) binary 165 * data to the given stream. 166 * 167 * @deprecated Set cfg.prefix and use the 3-parameter 168 * function instead. 169 * 170 * @param s stream to dump data to. 171 * @param data data to hex-dump. 172 * @param tag string to put at the beginning of each line of output. 173 * @param cfg formatting configuration. 174 */ 175 inline void hexDumpData(std::ostream& s, 176 const std::string& data, 177 const std::string& tag, 178 HexDumpDataConfig cfg = HexDumpDataConfig()); 179 180 /** 181 * Remove a string from the beginning of another string. 182 * Occurrences of the string \a aString appearing 183 * at the beginning of the string \a s are removed. 184 * @param s string to be stripped (modified). 185 * @param aString string to remove. 186 * @param num maximum number of occurrences to remove. 187 * @throw StringException if there's a std::exception thrown. 188 * @return a reference to \a s. 189 */ 190 inline 191 std::string& stripLeading(std::string& s, 192 const std::string& aString, 193 std::string::size_type num = std::string::npos); 194 195 /** 196 * Remove a string from the beginning of another string const version. 197 * Occurrences of the string \a aString appearing 198 * at the beginning of the string \a s are removed. 199 * @param s string to be stripped (modified). 200 * @param aString string to remove. 201 * @param num maximum number of occurrences to remove. 202 * @throw StringException if there's a std::exception thrown. 203 * @return a reference to \a s. 204 */ stripLeading(const std::string & s,const std::string & aString,std::string::size_type num=std::string::npos)205 inline std::string stripLeading(const std::string& s, 206 const std::string& aString, 207 std::string::size_type num = std::string::npos) 208 { std::string t(s); stripLeading(t, aString, num); return t; } 209 210 /** 211 * Remove a string from the beginning of another string. 212 * Occurrences of the string \a pString appearing 213 * at the beginning of the string \a s are removed. 214 * @param s string to be stripped (modified). 215 * @param pString string to remove. 216 * @param num maximum number of occurrences to remove. 217 * @throw StringException if there's a std::exception thrown. 218 * @return a reference to \a s. 219 */ stripLeading(std::string & s,const char * pString,std::string::size_type num=std::string::npos)220 inline std::string& stripLeading(std::string& s, 221 const char* pString, 222 std::string::size_type num = std::string::npos) 223 { return stripLeading(s, std::string(pString), num); } 224 225 /** 226 * Remove a string from the beginning of another string const version. 227 * Occurrences of the string \a pString appearing 228 * at the beginning of the string \a s are removed. 229 * @param s string to be stripped (modified). 230 * @param pString string to remove. 231 * @param num maximum number of occurrences to remove. 232 * @throw StringException if there's a std::exception thrown. 233 * @return a reference to \a s. 234 */ stripLeading(const std::string & s,const char * pString,std::string::size_type num=std::string::npos)235 inline std::string stripLeading(const std::string& s, 236 const char* pString, 237 std::string::size_type num = std::string::npos) 238 { std::string t(s); stripLeading(t, std::string(pString), num); return t; } 239 240 /** 241 * Strip character(s) from the beginning of a string. 242 * Occurrences of the character \a aCharacter appearing 243 * at the beginning of the string \a s are removed. 244 * @param s string to be stripped (modified). 245 * @param aCharacter character to remove. 246 * @param num maximum number of occurrences to remove. 247 * @throw StringException if there's a std::exception thrown. 248 * @return a reference to \a s. 249 */ stripLeading(std::string & s,const char aCharacter,std::string::size_type num=std::string::npos)250 inline std::string& stripLeading(std::string& s, 251 const char aCharacter, 252 std::string::size_type num = std::string::npos) 253 { return stripLeading(s, std::string(1,aCharacter), num); } 254 255 /** 256 * Strip character(s) from the beginning of a string const version. 257 * Occurrences of the character \a aCharacter appearing 258 * at the beginning of the string \a s are removed. 259 * @param s string to be stripped (modified). 260 * @param aCharacter character to remove. 261 * @param num maximum number of occurrences to remove. 262 * @throw StringException if there's a std::exception thrown. 263 * @return a reference to \a s. 264 */ stripLeading(const std::string & s,const char aCharacter,std::string::size_type num=std::string::npos)265 inline std::string stripLeading(const std::string& s, 266 const char aCharacter, 267 std::string::size_type num = std::string::npos) 268 { std::string t(s); stripLeading(t, std::string(1,aCharacter), num); return t; } 269 270 /** 271 * Strip blanks from the beginning of a string. 272 * Occurrences of the space character appearing 273 * at the beginning of the string \a s are removed. 274 * @param s string to be stripped (modified). 275 * @param num maximum number of occurrences to remove. 276 * @throw StringException if there's a std::exception thrown. 277 * @return a reference to \a s. 278 */ stripLeading(std::string & s,std::string::size_type num=std::string::npos)279 inline std::string& stripLeading(std::string& s, 280 std::string::size_type num = std::string::npos) 281 { return stripLeading(s,std::string(1,' '),num); } 282 283 /** 284 * Strip blanks from the beginning of a string const version. 285 * Occurrences of the space character appearing 286 * at the beginning of the string \a s are removed. 287 * @param s string to be stripped (modified). 288 * @param num maximum number of occurrences to remove. 289 * @throw StringException if there's a std::exception thrown. 290 * @return a reference to \a s. 291 */ stripLeading(const std::string & s,std::string::size_type num=std::string::npos)292 inline std::string stripLeading(const std::string& s, 293 std::string::size_type num = std::string::npos) 294 { std::string t(s); stripLeading(t,std::string(1,' '),num); return t; } 295 296 /** 297 * Remove a string from the end of another string. 298 * Occurrences of the string \a aString appearing 299 * at the end of the string \a s are removed. 300 * @param s string to be stripped (modified). 301 * @param aString string to remove. 302 * @param num maximum number of occurrences to remove. 303 * @throw StringException if there's a std::exception thrown. 304 * @return a reference to \a s. 305 */ 306 inline std::string& stripTrailing(std::string& s, 307 const std::string& aString, 308 std::string::size_type num = std::string::npos); 309 310 /** 311 * Remove a string from the end of another string const version. 312 * Occurrences of the string \a aString appearing 313 * at the end of the string \a s are removed. 314 * @param s string to be stripped (modified). 315 * @param aString string to remove. 316 * @param num maximum number of occurrences to remove. 317 * @throw StringException if there's a std::exception thrown. 318 * @return a reference to \a s. 319 */ stripTrailing(const std::string & s,const std::string & aString,std::string::size_type num=std::string::npos)320 inline std::string stripTrailing(const std::string& s, 321 const std::string& aString, 322 std::string::size_type num = std::string::npos) 323 { std::string t(s); stripTrailing(t, aString, num); return t;} 324 325 /** 326 * Remove a string from the end of another string. 327 * Occurrences of the string \a pString appearing 328 * at the end of the string \a s are removed. 329 * @param s string to be stripped (modified). 330 * @param pString string to remove. 331 * @param num maximum number of occurrences to remove. 332 * @throw StringException if there's a std::exception thrown. 333 * @return a reference to \a s. 334 */ stripTrailing(std::string & s,const char * pString,std::string::size_type num=std::string::npos)335 inline std::string& stripTrailing(std::string& s, 336 const char* pString, 337 std::string::size_type num = std::string::npos) 338 { return stripTrailing(s, std::string(pString), num); } 339 340 /** 341 * Remove a string from the end of another string const version. 342 * Occurrences of the string \a pString appearing 343 * at the end of the string \a s are removed. 344 * @param s string to be stripped (modified). 345 * @param pString string to remove. 346 * @param num maximum number of occurrences to remove. 347 * @throw StringException if there's a std::exception thrown. 348 * @return a reference to \a s. 349 */ stripTrailing(const std::string & s,const char * pString,std::string::size_type num=std::string::npos)350 inline std::string stripTrailing(const std::string& s, 351 const char* pString, 352 std::string::size_type num = std::string::npos) 353 { std::string t(s); stripTrailing(t, std::string(pString), num); return t; } 354 355 /** 356 * Strip character(s) from the end of a string. 357 * Occurrences of the character \a aCharacter appearing 358 * at the end of the string \a s are removed. 359 * @param s string to be stripped (modified). 360 * @param aCharacter character to remove. 361 * @param num maximum number of occurrences to remove. 362 * @throw StringException if there's a std::exception thrown. 363 * @return a reference to \a s. 364 */ stripTrailing(std::string & s,const char aCharacter,std::string::size_type num=std::string::npos)365 inline std::string& stripTrailing(std::string& s, 366 const char aCharacter, 367 std::string::size_type num = std::string::npos) 368 { return stripTrailing(s, std::string(1,aCharacter), num); } 369 370 /** 371 * Strip character(s) from the end of a string const version. 372 * Occurrences of the character \a aCharacter appearing 373 * at the end of the string \a s are removed. 374 * @param s string to be stripped (modified). 375 * @param aCharacter character to remove. 376 * @param num maximum number of occurrences to remove. 377 * @throw StringException if there's a std::exception thrown. 378 * @return a reference to \a s. 379 */ stripTrailing(const std::string & s,const char aCharacter,std::string::size_type num=std::string::npos)380 inline std::string stripTrailing(const std::string& s, 381 const char aCharacter, 382 std::string::size_type num = std::string::npos) 383 { std::string t(s); stripTrailing(t, std::string(1,aCharacter), num); return t; } 384 385 /** 386 * Strip blanks from the end of a string. 387 * Occurrences of the space character appearing 388 * at the end of the string \a s are removed. 389 * @param s string to be stripped (modified). 390 * @param num maximum number of occurrences to remove. 391 * @throw StringException if there's a std::exception thrown. 392 * @return a reference to \a s. 393 */ stripTrailing(std::string & s,std::string::size_type num=std::string::npos)394 inline std::string& stripTrailing(std::string& s, 395 std::string::size_type num = std::string::npos) 396 { return stripTrailing(s, std::string(1,' '), num); } 397 398 /** 399 * Strip blanks from the end of a string const version. 400 * Occurrences of the space character appearing 401 * at the end of the string \a s are removed. 402 * @param s string to be stripped (modified). 403 * @param num maximum number of occurrences to remove. 404 * @throw StringException if there's a std::exception thrown. 405 * @return a reference to \a s. 406 */ stripTrailing(const std::string & s,std::string::size_type num=std::string::npos)407 inline std::string stripTrailing(const std::string& s, 408 std::string::size_type num = std::string::npos) 409 { std::string t(s); stripTrailing(t, std::string(1,' '), num); return t;} 410 411 /** 412 * Remove a string from the beginning and end of another string. 413 * Occurrences of the string \a aString appearing 414 * at the beginning and end of the string \a s are removed. 415 * @param s string to be stripped (modified). 416 * @param aString string to remove. 417 * @param num maximum number of occurrences to remove. 418 * @throw StringException if there's a std::exception thrown. 419 * @return a reference to \a s. 420 */ 421 inline std::string& strip(std::string& s, 422 const std::string& aString, 423 std::string::size_type num = std::string::npos); 424 425 426 /** 427 * Remove a string from the beginning and end of another string const version. 428 * Occurrences of the string \a aString appearing 429 * at the beginning and end of the string \a s are removed. 430 * @param s string to be stripped (modified). 431 * @param aString string to remove. 432 * @param num maximum number of occurrences to remove. 433 * @throw StringException if there's a std::exception thrown. 434 * @return a reference to \a s. 435 */ strip(const std::string & s,const std::string & aString,std::string::size_type num=std::string::npos)436 inline std::string strip(const std::string& s, 437 const std::string& aString, 438 std::string::size_type num = std::string::npos) 439 { std::string t(s); strip(t, aString, num); return t; } 440 441 442 /** 443 * Remove a string from the beginning and end of another string. 444 * Occurrences of the string \a pString appearing 445 * at the beginning and end of the string \a s are removed. 446 * @param s string to be stripped (modified). 447 * @param pString string to remove. 448 * @param num maximum number of occurrences to remove. 449 * @throw StringException if there's a std::exception thrown. 450 * @return a reference to \a s. 451 */ strip(std::string & s,const char * pString,std::string::size_type num=std::string::npos)452 inline std::string& strip(std::string& s, 453 const char* pString, 454 std::string::size_type num = std::string::npos) 455 { return strip(s, std::string(pString), num); } 456 457 /** 458 * Remove a string from the beginning and end of another string cosnt version. 459 * Occurrences of the string \a pString appearing 460 * at the beginning and end of the string \a s are removed. 461 * @param s string to be stripped (modified). 462 * @param pString string to remove. 463 * @param num maximum number of occurrences to remove. 464 * @throw StringException if there's a std::exception thrown. 465 * @return a reference to \a s. 466 */ strip(const std::string & s,const char * pString,std::string::size_type num=std::string::npos)467 inline std::string strip(const std::string& s, 468 const char* pString, 469 std::string::size_type num = std::string::npos) 470 { std::string t(s); strip(t, std::string(pString), num); return t; } 471 472 /** 473 * Strip character(s) from the beginning and end of a string. 474 * Occurrences of the character \a aCharacter appearing 475 * at the beginning and end of the string \a s are removed. 476 * @param s string to be stripped (modified). 477 * @param aCharacter character to remove. 478 * @param num maximum number of occurrences to remove. 479 * @throw StringException if there's a std::exception thrown. 480 * @return a reference to \a s. 481 */ strip(std::string & s,const char aCharacter,std::string::size_type num=std::string::npos)482 inline std::string& strip(std::string& s, 483 const char aCharacter, 484 std::string::size_type num = std::string::npos) 485 { return strip(s, std::string(1,aCharacter), num); } 486 487 /** 488 * Strip character(s) from the beginning and end of a string const version. 489 * Occurrences of the character \a aCharacter appearing 490 * at the beginning and end of the string \a s are removed. 491 * @param s string to be stripped (modified). 492 * @param aCharacter character to remove. 493 * @param num maximum number of occurrences to remove. 494 * @throw StringException if there's a std::exception thrown. 495 * @return a reference to \a s. 496 */ strip(const std::string & s,const char aCharacter,std::string::size_type num=std::string::npos)497 inline std::string strip(const std::string& s, 498 const char aCharacter, 499 std::string::size_type num = std::string::npos) 500 { std::string t(s); strip(t, std::string(1,aCharacter), num); return t;} 501 502 /** 503 * Strip blanks from the beginning and end of a string. 504 * Occurrences of the space character appearing 505 * at the beginning and end of the string \a s are removed. 506 * @param s string to be stripped (modified). 507 * @param num maximum number of occurrences to remove. 508 * @throw StringException if there's a std::exception thrown. 509 * @return a reference to \a s. 510 */ strip(std::string & s,std::string::size_type num=std::string::npos)511 inline std::string& strip(std::string& s, 512 std::string::size_type num = std::string::npos) 513 { return strip(s, std::string(1, ' '), num); } 514 515 /** 516 * Strip blanks from the beginning and end of a string const version. 517 * Occurrences of the space character appearing 518 * at the beginning and end of the string \a s are removed. 519 * @param s string to be stripped (modified). 520 * @param num maximum number of occurrences to remove. 521 * @throw StringException if there's a std::exception thrown. 522 * @return a reference to \a s. 523 */ strip(const std::string & s,std::string::size_type num=std::string::npos)524 inline std::string strip(const std::string& s, 525 std::string::size_type num = std::string::npos) 526 { std::string t(s); strip(t, std::string(1, ' '), num); return t;} 527 528 /** 529 * Converts all of the receiver's characters that are in the 530 * first specified string to the corresponding character in 531 * the second specified string. 532 * @param aString string to perform translation on. 533 * @param inputChars characters in \a aString to translate from. 534 * @param outputChars characters to translate to. 535 * @param pad pad character in the event inputChars and 536 * outputChars are not equal length. The pad character will 537 * become the translated character. 538 */ 539 inline std::string translate(const std::string& aString, 540 const std::string& inputChars, 541 const std::string& outputChars, 542 const char pad = ' '); 543 544 /** 545 * Changes occurrences of a specified pattern to a specified 546 * replacement string. You can specify the number of changes 547 * to perform. The default is to change all occurrences of 548 * the pattern. You can also specify the position in the 549 * receiver at which to begin. 550 * @param aString string to perform translation on. 551 * @param inputString The pattern string as a reference to an 552 * object of type string. The library searches for the 553 * pattern string within the receiver's data. 554 * @param outputString The replacement string as a reference 555 * to an object of type string. It replaces the occurrences 556 * of the pattern string in the receiver's data. 557 * @param startPos The position to start the search at within 558 * the receiver's data. The default is 0. 559 * @param numChanges the number of patterns to search for and 560 * change. The default is to change all occurrences of the 561 * pattern. 562 */ 563 inline std::string change(const std::string& aString, 564 const std::string& inputString, 565 const std::string& outputString, 566 std::string::size_type startPos = 0, 567 unsigned numChanges = (std::numeric_limits<unsigned>::max)()); 568 569 /** 570 * Changes occurrences of a specified pattern to a specified 571 * replacement string. You can specify the number of changes 572 * to perform. The default is to change all occurrences of 573 * the pattern. You can also specify the position in the 574 * receiver at which to begin. 575 * @param aString string to perform translation on. 576 * @param inputString The pattern string as a reference to an 577 * object of type string. The library searches for the 578 * pattern string within the receiver's data. 579 * @param outputString The replacement string as a reference 580 * to an object of type string. It replaces the occurrences 581 * of the pattern string in the receiver's data. 582 * @param startPos The position to start the search at within 583 * the receiver's data. The default is 0. 584 * @param numChanges the number of patterns to search for and 585 * change. The default is to change all occurrences of the 586 * pattern. 587 */ 588 inline std::string& change(std::string& aString, 589 const std::string& inputString, 590 const std::string& outputString, 591 std::string::size_type startPos = 0, 592 unsigned numChanges = (std::numeric_limits<unsigned>::max)()); 593 594 /** 595 * Right-justifies the receiver in a string of the specified 596 * length. If the receiver's data is shorter than the 597 * requested length (\a length), it is padded on the left with 598 * the pad character (\a pad). The default pad 599 * character is a blank. 600 * @param s string to be modified. 601 * @param length new desired length of string. 602 * @param pad character to pad string with (blank by default). 603 * @throw StringException if there's a std::exception thrown. 604 * @return a reference to \a s. */ 605 inline std::string& rightJustify(std::string& s, 606 const std::string::size_type length, 607 const char pad = ' '); 608 609 /** 610 * Right-justifies the receiver in a string of the specified 611 * length (const version). If the receiver's data is shorter than the 612 * requested length (\a length), it is padded on the left with 613 * the pad character (\a pad). The default pad 614 * character is a blank. 615 * @param s string to be modified. 616 * @param length new desired length of string. 617 * @param pad character to pad string with (blank by default). 618 * @throw StringException if there's a std::exception thrown. 619 * @return a reference to \a s. */ rightJustify(const std::string & s,const std::string::size_type length,const char pad=' ')620 inline std::string rightJustify(const std::string& s, 621 const std::string::size_type length, 622 const char pad = ' ') 623 { std::string t(s); return rightJustify(t, length, pad); } 624 625 /** 626 * Left-justifies the receiver in a string of the specified 627 * length. If the new length (\a length) is larger than the 628 * current length, the string is extended by the pad 629 * character (\a pad). The default pad character is a 630 * blank. 631 * @param s string to be modified. 632 * @param length new desired length of string. 633 * @param pad character to pad string with (blank by default). 634 * @throw StringException if there's a std::exception thrown. 635 * @return a reference to \a s. */ 636 inline std::string& leftJustify(std::string& s, 637 const std::string::size_type length, 638 const char pad = ' '); 639 640 /** 641 * Left-justifies the receiver in a string of the specified 642 * length (const version). If the new length (\a length) is larger 643 * than the current length, the string is extended by the pad 644 * character (\a pad). The default pad character is a 645 * blank. 646 * @param s string to be modified. 647 * @param length new desired length of string. 648 * @param pad character to pad string with (blank by default). 649 * @throw StringException if there's a std::exception thrown. 650 * @return a reference to \a s. */ leftJustify(const std::string & s,const std::string::size_type length,const char pad=' ')651 inline std::string leftJustify(const std::string& s, 652 const std::string::size_type length, 653 const char pad = ' ') 654 { std::string t(s); return leftJustify(t, length, pad); } 655 656 /** 657 * Change the length of a string by adding to the beginning and end. 658 * The string \a s is modified to the specified 659 * length. If the string is shorter than 660 * \a length, then the string is truncated with the 661 * left-most \a length characters remaining. 662 * Otherwise, characters are added to the beginning and end of the 663 * string until the string is the specified length, where the 664 * number of characters added to the beginning and the end 665 * does not differ by more than one so the original string 666 * is centered. 667 * @param s string to be modified. 668 * @param length new desired length of string. 669 * @param pad character to pad string with (blank by default). 670 * @throw StringException if there's a std::exception thrown. 671 * @return a reference to \a s. 672 */ 673 inline std::string& center(std::string& s, 674 const std::string::size_type length, 675 const char pad = ' '); 676 677 /** 678 * Change the length of a string by adding to the beginning and end 679 * (const version). 680 * The string \a s is modified to the specified 681 * length. If the string is shorter than 682 * \a length, then the string is truncated with the 683 * left-most \a length characters remaining. 684 * Otherwise, characters are added to the beginning and end of the 685 * string until the string is the specified length, where the 686 * number of characters added to the beginning and the end 687 * does not differ by more than one so the original string 688 * is centered. 689 * @param s string to be modified. 690 * @param length new desired length of string. 691 * @param pad character to pad string with (blank by default). 692 * @throw StringException if there's a std::exception thrown. 693 * @return a reference to \a s. 694 */ center(const std::string & s,const std::string::size_type length,const char pad=' ')695 inline std::string center(const std::string& s, 696 const std::string::size_type length, 697 const char pad = ' ') 698 { std::string t(s); return center(t, length, pad); } 699 700 /** 701 * Convert a string to a double precision floating point number. 702 * @param s string containing a number. 703 * @return double representation of string. 704 */ asDouble(const std::string & s)705 inline double asDouble(const std::string& s) 706 { return strtod(s.c_str(), 0); } 707 708 /** 709 * Convert a string to an integer. 710 * @param s string containing a number. 711 * @return long integer representation of string. 712 */ asInt(const std::string & s)713 inline long asInt(const std::string& s) 714 { return strtol(s.c_str(), 0, 10); } 715 716 /** 717 * Convert a string to an unsigned integer. 718 * @param s string containing a number. 719 * @return unsigned long integer representation of string. 720 */ asUnsigned(const std::string & s)721 inline unsigned long asUnsigned(const std::string& s) 722 { return strtoul(s.c_str(), 0, 10); } 723 724 /** 725 * Convert a string to a single precision floating point number. 726 * @param s string containing a number. 727 * @return single representation of string. 728 * @throw StringException 729 */ 730 inline float asFloat(const std::string& s); 731 732 /** 733 * Convert a string to a big precision floating point number. 734 * @param s string containing a number. 735 * @return long double representation of string. 736 * @throw StringException 737 */ 738 inline long double asLongDouble(const std::string& s); 739 740 /** 741 * Convert a value in a string to a type specified by the template 742 * class. The template class type must have stream operators 743 * defined. 744 * @param s object to turn into the templatized type. 745 * @return the template object of \a x. 746 * @throw StringException 747 */ 748 template <class X> 749 inline X asData(const std::string& s); 750 751 /** 752 * Convert a long double to a string in fixed notation. 753 * @param x long double. 754 * @param precision the number of decimal places you want displayed. 755 * @return string representation of \a x. 756 */ 757 inline std::string asString(const long double x, 758 const std::string::size_type precision = 21); 759 760 /** 761 * Convert a double to a string in fixed notation. 762 * @param x double. 763 * @param precision the number of decimal places you want displayed. 764 * @return string representation of \a x. 765 */ 766 inline std::string asString(const double x, 767 const std::string::size_type precision = 17); 768 769 /** 770 * Convert any old object to a string. 771 * The class must have stream operators defined. 772 * @param x object to turn into a string. 773 * @return string representation of \a x. 774 */ 775 template <class X> 776 inline std::string asString(const X x); 777 778 /** 779 * Convert a decimal string to a hexadecimal string. 780 * Modify the string such that the decimal integer is now 781 * represented as hexadecimal. Only the first decimal encountered is 782 * changed; the rest of the string is unmodified. 783 * @param s string containing an integer. 784 * @return reference to modified \a s. 785 * @throw StringException 786 */ 787 inline std::string& d2x(std::string& s); 788 789 /** 790 * Convert a decimal string to a hexadecimal string. 791 * Given a string containing a decimal integer, convert the 792 * integer from base 10 to base 16 and return the result. No 793 * prefix is added. Only the first decimal encountered is 794 * changed; the rest of the string is unmodified. 795 * @param s string containing an integer. 796 * @return string containing a hexadecimal number. 797 * @throw StringException 798 */ d2x(const std::string & s)799 inline std::string d2x(const std::string& s) 800 { std::string t(s); return d2x(t); } 801 802 /** 803 * Convert a hexadecimal string to a decimal string. 804 * Modify the string such that the hexadecimal number is now 805 * represented as decimal. Only the first hex number encountered 806 * is changed; the rest of the string is unmodified. 807 * @param s string containing an integer. 808 * @return reference to modified \a s. 809 * @throw StringException 810 */ 811 inline std::string& x2d(std::string& s); 812 813 /** 814 * Convert a hexadecimal string to a decimal string. 815 * Given a string containing a hexadecimal number, convert the 816 * integer from base 16 to base 10 and return the result. 817 * Only the first hex number encountered 818 * is changed; the rest of the string is unmodified. 819 * @param s string containing an integer. 820 * @return string containing a hexadecimal number. 821 * @throw StringException 822 */ x2d(const std::string & s)823 inline std::string x2d(const std::string& s) 824 { std::string t(s); return x2d(t); } 825 826 /** 827 * Convert a character string to a hexadecimal string. 828 * Modify the string such that the character string is now 829 * represented as series of hexadecimal digits. 830 * @param s string to convert. 831 * @return reference to modified \a s. 832 * @throw StringException 833 */ 834 inline std::string& c2x(std::string& s); 835 836 /** 837 * Convert a character string to a hexadecimal string. 838 * @param s string containing an integer. 839 * @return string containing a sequence of hexadecimal numbers. 840 * @throw StringException 841 */ c2x(const std::string & s)842 inline std::string c2x(const std::string& s) 843 { std::string t(s); return c2x(t); } 844 845 /** 846 * Convert a hexadecimal string to an unsigned int. 847 * Only the first hex number encountered is converted. 848 * @param s string containing a hex integer. 849 * @return a long holding the value of \a s. 850 * @throw StringException 851 */ 852 inline unsigned int x2uint(const std::string& s); 853 854 /** 855 * Convert an int to a string. 856 * @param i the integer to convert 857 * @return a string with the hex equivalent of i 858 * @throw StringException 859 */ 860 inline std::string int2x(const unsigned int& i); 861 862 /** 863 * Replace all instances of \a oldString with \a newString in \a s. 864 * @param s the string whose contents will be modified. 865 * @param oldString the string to search for in \a s. 866 * @param newString the string to replace \a oldString in \a s. 867 * @return a reference to the modified string. 868 * @throw StringException 869 */ 870 inline std::string& replaceAll(std::string& s, 871 const std::string& oldString, 872 const std::string& newString ); 873 874 /** 875 * isDigitString is exactly like the C function isDigit 876 * except it checks all the characters of string \a s to see if 877 * they are all digits. 878 * @param s the string to check the digits in. 879 * @return true if \a s is all digits, false otherwise. 880 */ 881 inline bool isDigitString(const std::string& s); 882 883 /** 884 * isDecimalString is like isDigitString() except it allows a 885 * single period ('.') character in the string. 886 * @param s the string to check. 887 * @return true if \a s is a valid fixed-point number. 888 */ 889 inline bool isDecimalString(const std::string& s); 890 891 /** 892 * isScientificString extends isDecimalString() to allow a single 893 * exponent (E,e,D,d) character between a decimal string and 894 * a (possibly empty) digit string. 895 * @param s the string to check. 896 * @return true if \a s is a valid scientific-notation number. 897 */ 898 inline bool isScientificString(const std::string& s); 899 900 /** 901 * isAlphaString is exactly like the C function isAlpha 902 * except it checks all the characters of string \a s to see if 903 * they are all alphabet characters. 904 * @param s the string to check the characters in. 905 * @return true if \a s is all digits, false otherwise. 906 */ 907 inline bool isAlphaString(const std::string& s); 908 909 /** 910 * Perform pattern matching on strings. 911 * Looks for a pattern in a string. Wildcards are allowed. 912 * Uses POSIX regular expressions. 913 * @param s string to search. 914 * @param aPattern pattern to search for. This is a POSIX 915 * regular expression. 916 * @param zeroOrMore character representing wildcards 917 * matching strings of zero or more characters (default '*'). 918 * @param oneOrMore character representing plus sign 919 * matching strings of one or more characters (default '+'). 920 * @param anyChar character representing wildcards matching a 921 * single arbitrary character (default '.'). 922 * @return string representing the first match of \a aPattern in 923 * \a s. Returns a null string if no match is found. 924 * @throw StringException 925 */ 926 inline std::string matches(const std::string& s, 927 const std::string& aPattern, 928 const char zeroOrMore = '*', 929 const char oneOrMore = '+', 930 const char anyChar = '.' ); 931 932 /** 933 * Perform pattern matching on strings. 934 * Looks for a pattern in a string. Wildcards are allowed. 935 * Uses POSIX regular expressions. 936 * @param s string to search. 937 * @param aPattern pattern to search for. This is a POSIX 938 * regular expression. 939 * @param zeroOrMore character representing wildcards 940 * matching strings of zero or more characters (default '*'). 941 * @param oneOrMore character representing plus sign 942 * matching strings of one or more characters (default '+'). 943 * @param anyChar character representing wildcards matching a 944 * single arbitrary character (default '.'). 945 * @return t if a match is found, f if not. 946 * @throw StringException 947 */ isLike(const std::string & s,const std::string & aPattern,const char zeroOrMore='*',const char oneOrMore='+',const char anyChar='.')948 inline bool isLike(const std::string& s, 949 const std::string& aPattern, 950 const char zeroOrMore = '*', 951 const char oneOrMore = '+', 952 const char anyChar = '.' ) 953 { return matches(s, aPattern, zeroOrMore, oneOrMore, anyChar) != 954 std::string(); } 955 956 957 /** 958 * Perform pattern matching on strings. 959 * Looks for a pattern in a string. Wildcards are allowed. 960 * Uses POSIX regular expressions. 961 * @param s string to search. 962 * @param pPattern pattern to search for. This is a POSIX 963 * regular expression. 964 * @param zeroOrMore character representing wildcards 965 * matching strings of zero or more characters (default '*'). 966 * @param oneOrMore character representing plus sign 967 * matching strings of one or more characters (default '+'). 968 * @param anyChar character representing wildcards matching a 969 * single arbitrary character (default '.'). 970 * @return t if a match is found, f if not. 971 * @throw StringException 972 */ isLike(const std::string & s,const char * pPattern,const char zeroOrMore='*',const char oneOrMore='+',const char anyChar='.')973 inline bool isLike(const std::string& s, 974 const char* pPattern, 975 const char zeroOrMore = '*', 976 const char oneOrMore = '+', 977 const char anyChar = '.' ) 978 { return matches(s, std::string(pPattern), 979 zeroOrMore, oneOrMore, anyChar) != std::string(); } 980 981 982 /** 983 * Work-horse method for printf. Substitutes patterns 984 * matching \a pat with \a rep. Use only one pattern/token 985 * at a time! This used to be DayTime::iprint(). 986 * @param fmt format to use for this time. 987 * @param pat regular expression pattern to match. 988 * @param rep sprintf token replacement. First character is 989 * token character used in fmt, remainder is sprintf token to 990 * use. For example, with fmt="%15S", pat="%[ 0-]?[[:digit:]]*S", 991 * and rep="Sd", the fmt will be translated to "%15d" before 992 * using it in a sprintf call like printf("%15d"), \a to. 993 * @param to the value to stuff into the string. 994 * @return \a fmt with \a pat replaced by \a to. If there is no 995 * match, \a fmt is returned unchanged. 996 * @throw StringException 997 */ 998 template <class T> 999 std::string formattedPrint(const std::string& fmt, 1000 const std::string& pat, 1001 const std::string& rep, 1002 T to); 1003 1004 /** 1005 * Get a substring of a string. 1006 * Try to avoid using this, use the stl string's substr 1007 * method instead (and ::leftJustify if needed). 1008 * @throw StringException 1009 */ 1010 inline std::string subString(const std::string& s, 1011 const std::string::size_type startPos = 0, 1012 const std::string::size_type length = std::string::npos, 1013 const char pad = ' ' ); 1014 1015 /** 1016 * Change all upper-case letters in a string to lower-case. 1017 * \a s is modified as a result. 1018 * @param s string to change to lower case. 1019 * @return a copy of the original string, all in lower-case. 1020 */ 1021 inline std::string& lowerCase(std::string& s); 1022 1023 /** 1024 * Change all upper-case letters in a string to lower-case. 1025 * Does not modify the original string. 1026 * @param s a string containing upper-case characters. 1027 * @return a copy of the original string, all in lower-case. 1028 */ lowerCase(const std::string & s)1029 inline std::string lowerCase(const std::string& s) 1030 { std::string t(s); return lowerCase(t); } 1031 1032 /** 1033 * Change all lower-case letters in a string to upper-case. 1034 * \a s is modified as a result. 1035 * @param s string to change to upper case. 1036 * @return a copy of the original string, all in upper-case. 1037 */ 1038 inline std::string& upperCase(std::string& s); 1039 1040 /** 1041 * Change all lower-case letters in a string to upper-case. 1042 * Does not modify the original string. 1043 * @param s a string containing lower-case characters. 1044 * @return a copy of the original string, all in upper-case. 1045 */ upperCase(const std::string & s)1046 inline std::string upperCase(const std::string& s) 1047 { std::string t(s); return upperCase(t); } 1048 1049 /** 1050 * Make a string from a void pointer. 1051 * This function should not be used. Instead, use the string 1052 * constructor as follows: 1053 * \code string((char*)p, size); \endcode 1054 * @param p pointer to memory. 1055 * @param size length of the data to turn into a string. 1056 * @return string object containing the contents of \a p. 1057 */ 1058 inline std::string memToString(const void* p, 1059 const std::string::size_type size); 1060 1061 /** 1062 * Returns the first word in string \a s without modifying the string. 1063 * @param s the string to count the words from. 1064 * @param delimiter the character that marks the start and 1065 * end of a word. 1066 * @return the first word from \a s; 1067 * @throw StringException 1068 */ 1069 inline std::string firstWord(const std::string& s, 1070 const char delimiter = ' '); 1071 1072 /** 1073 * Counts the number of words in \a s and returns it. 1074 * @param s the string to count the words from. 1075 * @param delimiter the character that marks the start and 1076 * end of a word. 1077 * @return the number of words in \a s. 1078 * @throw StringException 1079 */ 1080 inline int numWords(const std::string& s, 1081 const char delimiter = ' '); 1082 1083 /** 1084 * Returns \a numWords words starting with \a firstWord from 1085 * \a s (if any). 1086 * @param s a string with the word you want removed. 1087 * @param firstWord the number of the first word you want from \a s. 1088 * The first word is word 0. 1089 * @param numWords number of words to get from \a s. 1090 * @param delimiter the character that marks the start and 1091 * end of a word. 1092 * @return the first word from \a s or an empty string if there is 1093 * no \a wordNum'th word. 1094 * @throw StringException 1095 */ 1096 inline std::string words(const std::string& s, 1097 const std::string::size_type firstWord = 0, 1098 const std::string::size_type numWords = std::string::npos, 1099 const char delimiter = ' '); 1100 1101 /** 1102 * Returns word number \a wordNum from \a s (if any). 1103 * @param s a string with the word you want removed. 1104 * @param wordNum the number of the word you want from \a s. 1105 * The first word is word 0. 1106 * @param delimiter the character that marks the start and 1107 * end of a word. 1108 * @return the first word from \a s or an empty string if there is 1109 * no \a wordNum'th word. 1110 * @throw StringException 1111 */ word(const std::string & s,const std::string::size_type wordNum=0,const char delimiter=' ')1112 inline std::string word(const std::string& s, 1113 const std::string::size_type wordNum = 0, 1114 const char delimiter = ' ') 1115 { return words(s, wordNum, 1, delimiter); } 1116 1117 /** 1118 * Removes the first word off string \a s and returns it. 1119 * \a s is modified as a result. 1120 * @param s a string with the word you want removed. 1121 * @param delimiter the character that marks the start and 1122 * end of a word. 1123 * @return the first word from \a s 1124 * @throw StringException 1125 */ 1126 inline std::string stripFirstWord(std::string& s, 1127 const char delimiter = ' '); 1128 1129 /** 1130 * Split a string \a str into words as defined by \a delimiter. 1131 * @param str string to be parsed. 1132 * @param delimiter character that marks the start and end of a word. 1133 * @return a vector of the words (strings) 1134 * @throw StringException 1135 */ 1136 inline std::vector<std::string> split(const std::string& str, 1137 const char delimiter = ' '); 1138 1139 /** 1140 * Remove indicated words from the string \a s. 1141 * \a s is modified as a result. Removal of a word begins at the 1142 * start of the word and continues to include any delimiters between 1143 * the end of the word and the start of the next word. 1144 * If the last word in \a s is removed, all trailing delimiters 1145 * are removed as well; if all words in \a s are removed, the 1146 * resulting string is empty. 1147 * @param s a string with words to be removed. 1148 * @param first the first word to be removed (the first word is 0). 1149 * @param wordsToReplace the number of words to remove, 1150 * or std::string::npos to remove all subsequent words 1151 * @param delimiter character that marks the start and end of words 1152 * @return a reference to string \a s with the words removed. 1153 * @throw StringException 1154 */ 1155 inline std::string& removeWords(std::string& s, 1156 const std::string::size_type first = 0, 1157 const std::string::size_type wordsToReplace = std::string::npos, 1158 const char delimiter = ' '); 1159 1160 /** 1161 * Convert a double to a scientific notation number. 1162 * @param d the double to convert 1163 * @param length length (in characters) of output, including exponent 1164 * @param expLen length (in characters) of the exponent, with sign 1165 * @param showSign if true, reserves 1 character for +/- sign 1166 * @param checkSwitch if true, keeps the exponential sanity check for 1167 * exponentials above three characters in length. If false, it removes 1168 * that check. 1169 * @deprecated This method is being replaced by 1170 * FormattedDouble and is scheduled for removal in the first 1171 * tagged release of Q4 2020. 1172 */ 1173 inline std::string doub2sci(const double& d, 1174 const std::string::size_type length, 1175 const std::string::size_type expLen, 1176 const bool showSign = true, 1177 const bool checkSwitch = true); 1178 1179 /** Convert a double to scientific notation; this routine works better, 1180 * on Windows particularly, than doub2sci. 1181 * @param length = total string length, 1182 * including 1 for overall sign if showPlus is true. 1183 * @param precision = number of digits after the decimal and before the 'e' 1184 * @param explen = length of exponent, this must = 1, 2 or 3 1185 * NB. length is increased if precision, explen and showPlus require it. 1186 * @deprecated This method is being replaced by 1187 * FormattedDouble and is scheduled for removal in the first 1188 * tagged release of Q4 2020. 1189 */ 1190 inline std::string doubleToScientific(const double& d, 1191 const std::string::size_type length, 1192 const std::string::size_type precision, 1193 const std::string::size_type explen, 1194 bool showPlus=false); 1195 1196 /** 1197 * Convert scientific notation to FORTRAN notation. 1198 * As an example, the string "1.5636E5" becomes " .15636D6". 1199 * Note that the first character of the string will be '-' if 1200 * the number is negative or ' ' if the first character is positive. 1201 * @param aStr string with number to convert 1202 * @param startPos start position of number in string 1203 * @param length length (in characters) of number, including exponent. 1204 * @param expLen length (in characters of exponent, not including sign. 1205 * @param checkSwitch will keep the method running as 1206 * originally programmed when set to true. If false, the 1207 * method will always resize exponentials, produce an 1208 * exponential with an E instead of a D, and always have a 1209 * leading zero. For example -> 0.87654E-0004 or 1210 * -0.1234E00005. 1211 * @throw StringException if the string is not a number in 1212 * scientific notation 1213 * @deprecated This method is being replaced by 1214 * FormattedDouble and is scheduled for removal in the first 1215 * tagged release of Q4 2020. 1216 */ 1217 inline std::string& sci2for(std::string& aStr, 1218 const std::string::size_type startPos = 0, 1219 const std::string::size_type length = std::string::npos, 1220 const std::string::size_type expLen = 3, 1221 const bool checkSwitch = true); 1222 1223 /** 1224 * Convert double precision floating point to a string 1225 * containing the number in FORTRAN notation. 1226 * As an example, the number 156360 becomes ".15636D6". 1227 * @param d number to convert. 1228 * @param length length (in characters) of number, including exponent. 1229 * @param expLen length (in characters of exponent, including sign. 1230 * @param checkSwitch if true, keeps the exponential sanity check for 1231 * exponentials above three characters in length. If false, it removes 1232 * that check. 1233 * @return a string containing \a d in FORTRAN notation. 1234 * @throw StringException 1235 * @bug The rendered width is not correct if checkSwitch=false 1236 * @deprecated This method is being replaced by 1237 * FormattedDouble and is scheduled for removal in the first 1238 * tagged release of Q4 2020. 1239 */ 1240 inline std::string doub2for(const double& d, 1241 const std::string::size_type length, 1242 const std::string::size_type expLen, 1243 const bool checkSwitch = true); 1244 1245 /** 1246 * Convert FORTRAN representation of a double precision 1247 * floating point in a string to a number. 1248 * As an example, the number ".15636D6" becomes 156360. 1249 * @param aStr string containing FORTRAN representation of number. 1250 * @param startPos beginning of number in string. 1251 * @param length length (in characters) of number, including exponent. 1252 * @return value of the number. 1253 * @deprecated This method is being replaced by 1254 * FormattedDouble and is scheduled for removal in the first 1255 * tagged release of Q4 2020. 1256 */ 1257 inline double for2doub(const std::string& aStr, 1258 const std::string::size_type startPos = 0, 1259 const std::string::size_type length = std::string::npos); 1260 1261 /** Format a floating point value according to rules not 1262 * directly supported by C++ stream I/O. 1263 * @see FormattedDouble which should generally be used rather 1264 * than using this function directly. 1265 * @param[in] d The value that is to be formatted in an ostream. 1266 * @param[in] lead How the lead-in to the value is to be formatted. 1267 * @param[in] mantissa How many digits of precision should be 1268 * in the mantissa, e.g. mantissa=5 could result in 1269 * something like 1.2345e+00. 1270 * @param[in] exponent How many digits of precision should be 1271 * in the exponent, e.g. exponent=3 could result in 1272 * something like 1.2345e+000. Exponents will always be at 1273 * least 2 characters in length. 1274 * @param[in] width The total number of characters in the 1275 * formatted value. If the length of the formatted value 1276 * including mantissa, exponent, sign, etc. is >= width, no 1277 * additional formatting will take place. If the length of 1278 * the formatted value is < width, it will be padded with 1279 * spaces according to align. 1280 * @param[in] expChar The character used to designate the 1281 * exponent, e.g. "e" or "E" or "D". 1282 * @param[in] sign How numerical sign is to be handled in formatting. 1283 * @param[in] align How to pad the formatted value according 1284 * to width. Left adds space to the end of the formatted 1285 * value while Right inserts space at the beginning. 1286 */ 1287 std::string floatFormat(double d, FFLead lead, unsigned mantissa, 1288 unsigned exponent, unsigned width = 0, 1289 char expChar = 'e', 1290 FFSign sign = FFSign::NegOnly, 1291 FFAlign align = FFAlign::Left); 1292 1293 /** 1294 * Change a string into printable characters. Control 1295 * characters 0, 1, ... 31 are changed to ^@, ^A, ... ^_ ; 1296 * control character 127 is changed to ^? (as per Caret-notation). 1297 * Other non-printable characters are changed to hex sequences 1298 * enclosed in <>. 1299 * @param aStr the string to make printable. 1300 * @throw StringException 1301 */ 1302 inline std::string printable(const std::string& aStr); 1303 1304 /** 1305 * Nicely expands the input string into several lines, non-const 1306 * version. 1307 * @param aStr the string to be modified. 1308 * @param lineDelim a string to put between every line. 1309 * @param indent an indentataion string used on all but the first line 1310 * @param firstIndent is the indentation used on the first line. 1311 * @param len the maximum length of string to put on a line. 1312 * @param wordDelim the character that separates each word. 1313 * @return the string nicely formatted. 1314 * @throw StringException 1315 */ 1316 inline std::string& prettyPrint(std::string& aStr, 1317 const std::string& lineDelim = "\n", 1318 const std::string& indent = "", 1319 const std::string& firstIndent = " ", 1320 const std::string::size_type len = 80, 1321 const char wordDelim = ' '); 1322 1323 /** 1324 * Const version of prettyPrint, which nicely expands the 1325 * input string into several lines. 1326 * @param aStr the string to be modified. 1327 * @param lineDelim a string to put between every line. 1328 * @param indent an indentataion string used on all but the first line 1329 * @param firstIndent is the indentation used on the first line. 1330 * @param len the maximum length of string to put on a line. 1331 * @param wordDelim the character that separates each word. 1332 * @return the string nicely formatted. 1333 * @throw StringException 1334 */ prettyPrint(const std::string & aStr,const std::string & lineDelim="\\n",const std::string & indent="",const std::string & firstIndent=" ",const std::string::size_type len=80,const char wordDelim=' ')1335 inline std::string prettyPrint(const std::string& aStr, 1336 const std::string& lineDelim = "\n", 1337 const std::string& indent = "", 1338 const std::string& firstIndent = " ", 1339 const std::string::size_type len = 80, 1340 const char wordDelim = ' ') 1341 { 1342 std::string temp(aStr); 1343 prettyPrint(temp, lineDelim, indent, firstIndent, len, wordDelim); 1344 return temp; 1345 } 1346 1347 /** Split a string by some delimiters 1348 * @param aStr the string to be split 1349 * @param theDelimiters the delimiters to split the string 1350 * @param trimWhitespace will trim the token string, default is false 1351 * @param ignoreEmpty will ignore the empty tokens, default is true 1352 */ 1353 inline std::vector<std::string> split(const std::string& aStr, 1354 const std::string& theDelimiters, 1355 bool trimWhitespace = false, 1356 bool ignoreEmpty = true); 1357 1358 /// Split a string on the given delimiter, respecting fields enclosed by 1359 /// a pair of either single or double quotes. Quotes are removed in output, 1360 /// and optionally also leading and trailing whitespace. 1361 /// @param aStr the string to be split 1362 /// @param delimiter character delimiter (not ' or ") 1363 /// @param trimWhitespace will trim the token string, default is true 1364 /// @param ignoreEmpty will ignore the empty tokens, default is true 1365 inline std::vector<std::string> splitWithQuotes(const std::string& aStr, 1366 const char delimiter = ' ', 1367 bool trimWhitespace = true, 1368 bool ignoreEmpty = true); 1369 1370 /// Split a string on the given delimiter, respecting fields enclosed by 1371 /// a pair of double quotes. Quotes are removed in output, and optionally 1372 /// also leading and trailing whitespace. 1373 /// @param aStr the string to be split 1374 /// @param delimiter character delimiter (not ") 1375 /// @param trimWhitespace will trim the token string, default is true 1376 /// @param ignoreEmpty will ignore the empty tokens, default is true 1377 inline std::vector<std::string> splitWithDoubleQuotes(const std::string& aStr, 1378 const char delimiter = ' ', 1379 bool trimWhitespace = true, 1380 bool ignoreEmpty = true); 1381 } // namespace StringUtils 1382 1383 } // namespace gpstk 1384 1385 // ################################################ 1386 // Implementations of inline functions follow 1387 // ################################################ 1388 1389 namespace gpstk 1390 { 1391 1392 namespace StringUtils 1393 { hexDumpData(std::ostream & s,const std::string & data,unsigned indent,const HexDumpDataConfig & cfg)1394 inline void hexDumpData(std::ostream& s, const std::string& data, 1395 unsigned indent, const HexDumpDataConfig& cfg) 1396 { 1397 std::string instr(indent, ' '); 1398 hexDumpData(s, data, instr, cfg); 1399 } 1400 hexDumpData(std::ostream & s,const std::string & data,const std::string & tag,HexDumpDataConfig cfg)1401 inline void hexDumpData(std::ostream& s, const std::string& data, 1402 const std::string& tag, 1403 HexDumpDataConfig cfg) 1404 { 1405 cfg.prefix = tag; 1406 hexDumpData(data, s, cfg); 1407 } 1408 1409 // Keep searching for aString at the start of s 1410 // until num == 0 or aString is not found at the start of s stripLeading(std::string & s,const std::string & aString,std::string::size_type num)1411 inline std::string& stripLeading(std::string& s, 1412 const std::string& aString, 1413 std::string::size_type num) 1414 { 1415 try 1416 { 1417 if (aString == "") 1418 return s; 1419 1420 while((num > 0) && 1421 (s.find(aString,0) == 0) && 1422 (s.length() > 0)) 1423 { 1424 s.erase(0,aString.length()); 1425 --num; 1426 } 1427 return s; 1428 } 1429 catch(std::exception &e) 1430 { 1431 StringException strexc("Exception thrown: " + std::string(e.what())); 1432 GPSTK_THROW(strexc); 1433 } 1434 } 1435 1436 // keep searching for aString at the end of s 1437 // until aString isn't found there or num == 0 stripTrailing(std::string & s,const std::string & aString,std::string::size_type num)1438 inline std::string& stripTrailing(std::string& s, 1439 const std::string& aString, 1440 std::string::size_type num) 1441 { 1442 try 1443 { 1444 // empty string, etc.; cannot let (size_type) pos = negative 1445 if (s.length() < aString.length() || (aString == "")) 1446 return s; 1447 1448 std::string::size_type pos = s.length() - aString.length(); 1449 1450 while((num > 0) && 1451 (s.length() >= aString.length()) && 1452 (s.rfind(aString,pos) == pos)) 1453 { 1454 s.erase(pos, std::string::npos); 1455 --num; 1456 pos = s.length() - aString.length(); 1457 } 1458 return s; 1459 } 1460 catch(std::exception &e) 1461 { 1462 StringException strexc("Exception thrown: " + std::string(e.what())); 1463 GPSTK_THROW(strexc); 1464 } 1465 } 1466 strip(std::string & s,const std::string & aString,std::string::size_type num)1467 inline std::string& strip(std::string& s, 1468 const std::string& aString, 1469 std::string::size_type num) 1470 { 1471 stripLeading(s, aString, num); 1472 stripTrailing(s, aString, num); 1473 return s; 1474 } 1475 translate(const std::string & aString,const std::string & inputChars,const std::string & outputChars,const char pad)1476 inline std::string translate(const std::string& aString, 1477 const std::string& inputChars, 1478 const std::string& outputChars, 1479 const char pad) 1480 { 1481 std::string rv = aString; 1482 std::string::size_type aspos = 0; 1483 std::string::size_type inpos = std::string::npos; 1484 char toc = pad; 1485 1486 // By starting at the last position, we avoid infinite 1487 // loops in case someone did something dumb, like, for 1488 // example, setting inputChars=outputChars. 1489 while ((aspos = rv.find_first_of(inputChars, aspos)) 1490 != std::string::npos) 1491 { 1492 // figure out which char we found; 1493 inpos = inputChars.find(rv[aspos]); 1494 if (outputChars.length()-1 < inpos) 1495 toc = pad; 1496 else 1497 toc = outputChars[inpos]; 1498 rv[aspos] = toc; 1499 1500 aspos++; // try to guarantee no infinite loops 1501 } 1502 1503 return rv; 1504 } 1505 change(const std::string & aString,const std::string & inputString,const std::string & outputString,std::string::size_type startPos,unsigned numChanges)1506 inline std::string change(const std::string& aString, 1507 const std::string& inputString, 1508 const std::string& outputString, 1509 std::string::size_type startPos, unsigned numChanges) 1510 { 1511 std::string rv(aString); 1512 change(rv, inputString, outputString, startPos, numChanges); 1513 return rv; 1514 } 1515 change(std::string & aString,const std::string & inputString,const std::string & outputString,std::string::size_type startPos,unsigned numChanges)1516 inline std::string& change(std::string& aString, const std::string& inputString, 1517 const std::string& outputString, 1518 std::string::size_type startPos, unsigned numChanges) 1519 { 1520 if(inputString.empty() || aString.empty()) return aString; 1521 unsigned count = 0; 1522 std::string::size_type opos = startPos; 1523 1524 while (count < numChanges) 1525 { 1526 std::string::size_type pos = aString.find(inputString, opos); 1527 if (pos != std::string::npos) 1528 { 1529 count++; 1530 aString.replace(pos, inputString.length(), outputString); 1531 opos = pos + outputString.length(); 1532 } 1533 else 1534 break; 1535 } 1536 1537 return aString; 1538 } 1539 1540 // if the string is bigger than length, truncate it from the left. 1541 // otherwise, add pad characters to it's left. rightJustify(std::string & s,const std::string::size_type length,const char pad)1542 inline std::string& rightJustify(std::string& s, 1543 const std::string::size_type length, 1544 const char pad) 1545 { 1546 try 1547 { 1548 if(length < s.length()) 1549 { 1550 s = s.substr(s.length()-length, std::string::npos); 1551 } 1552 else 1553 { 1554 s.insert((std::string::size_type)0, length-s.length(), pad); 1555 } 1556 return s; 1557 } 1558 catch(std::exception &e) 1559 { 1560 StringException strexc("Exception thrown: " + std::string(e.what())); 1561 GPSTK_THROW(strexc); 1562 } 1563 } 1564 1565 // if the string is bigger than length, truncate it from the right. 1566 // otherwise, add pad characters to it's right. leftJustify(std::string & s,const std::string::size_type length,const char pad)1567 inline std::string& leftJustify(std::string& s, 1568 const std::string::size_type length, 1569 const char pad) 1570 { 1571 try 1572 { 1573 if(length < s.length()) 1574 { 1575 s = s.substr(0, length); 1576 } 1577 else 1578 { 1579 s.append(length-s.length(), pad); 1580 } 1581 return s; 1582 } 1583 catch(std::exception &e) 1584 { 1585 StringException strexc("Exception thrown: " + std::string(e.what())); 1586 GPSTK_THROW(strexc); 1587 } 1588 } 1589 1590 // leftJustify if s is bigger than length. 1591 // otherwise, add pad to the left and right of s. center(std::string & s,const std::string::size_type length,const char pad)1592 inline std::string& center(std::string& s, 1593 const std::string::size_type length, 1594 const char pad) 1595 { 1596 try 1597 { 1598 if(length < s.length()) 1599 { 1600 leftJustify(s, length, pad); 1601 } 1602 else { 1603 std::string::size_type leftOff = s.length() + (length - s.length()) / 2; 1604 leftJustify(s, leftOff, pad); 1605 rightJustify(s, length, pad); 1606 } 1607 return s; 1608 } 1609 catch(StringException &e) 1610 { 1611 GPSTK_RETHROW(e); 1612 } 1613 catch(std::exception &e) 1614 { 1615 StringException strexc("Exception thrown: " + std::string(e.what())); 1616 GPSTK_THROW(strexc); 1617 } 1618 } 1619 1620 asFloat(const std::string & s)1621 inline float asFloat(const std::string& s) 1622 { 1623 try 1624 { 1625 std::istringstream is(s); 1626 float f; 1627 is >> f; 1628 return f; 1629 } 1630 catch(std::exception &e) 1631 { 1632 StringException strexc("Exception thrown: " + std::string(e.what())); 1633 GPSTK_THROW(strexc); 1634 } 1635 } 1636 asLongDouble(const std::string & s)1637 inline long double asLongDouble(const std::string& s) 1638 { 1639 try 1640 { 1641 std::istringstream is(s); 1642 long double x; 1643 is >> x; 1644 return x; 1645 } 1646 catch(std::exception &e) 1647 { 1648 StringException strexc("Exception thrown: " + std::string(e.what())); 1649 GPSTK_THROW(strexc); 1650 } 1651 } 1652 1653 template <class X> asData(const std::string & s)1654 inline X asData(const std::string& s) 1655 { 1656 try 1657 { 1658 std::istringstream is(s); 1659 X x; 1660 is >> x; 1661 return x; 1662 } 1663 catch(std::exception &e) 1664 { 1665 StringException strexc("Exception thrown: " + std::string(e.what())); 1666 GPSTK_THROW(strexc); 1667 } 1668 } 1669 asString(const long double x,const std::string::size_type precision)1670 inline std::string asString(const long double x, const std::string::size_type precision) 1671 { 1672 std::ostringstream ss; 1673 ss << std::fixed << std::setprecision(precision) << x ; 1674 return ss.str(); 1675 } 1676 asString(const double x,const std::string::size_type precision)1677 inline std::string asString(const double x, const std::string::size_type precision) 1678 { 1679 std::ostringstream ss; 1680 ss << std::fixed << std::setprecision(precision) << x; 1681 return ss.str(); 1682 } 1683 1684 template<class X> asString(const X x)1685 inline std::string asString(const X x) 1686 { 1687 std::ostringstream ss; 1688 ss << x; 1689 return ss.str(); 1690 } 1691 1692 // decimal to hex... d2x(std::string & s)1693 inline std::string& d2x(std::string& s) 1694 { 1695 try 1696 { 1697 // remove the integer from s, including 1698 // leading spaces and 0's 1699 long l = asInt(s); 1700 stripLeading(s); 1701 stripLeading(s, "0"); 1702 stripLeading(s, asString<long>(l)); 1703 1704 // put the int in a stringstream to convert it 1705 std::ostringstream st; 1706 st << std::hex << l << std::dec; 1707 1708 // add the new hex to s 1709 s.insert(0, upperCase(st.str()) ); 1710 1711 return s; 1712 } 1713 catch(StringException &e) 1714 { 1715 GPSTK_RETHROW(e); 1716 } 1717 catch(std::exception &e) 1718 { 1719 StringException strexc("Exception thrown: " + std::string(e.what())); 1720 GPSTK_THROW(strexc); 1721 } 1722 } 1723 1724 // character to hex... c2x(std::string & s)1725 inline std::string& c2x(std::string& s) 1726 { 1727 const char hexDigits[] = "0123456789ABCDEF"; 1728 try 1729 { 1730 std::string old(s); 1731 const unsigned char *pSource = (unsigned char *)old.c_str(); 1732 unsigned n = old.length(); 1733 1734 s.resize(n * 2, 0); 1735 1736 for (int i = 0; i < (int)n * 2;) 1737 { 1738 unsigned char c = *pSource++; 1739 s[i++] = hexDigits[ c / 16 ]; 1740 s[i++] = hexDigits[ c % 16 ]; 1741 } 1742 1743 return s; 1744 } 1745 catch(StringException &e) 1746 { 1747 GPSTK_RETHROW(e); 1748 } 1749 catch(std::exception &e) 1750 { 1751 StringException strexc("Exception thrown: " + std::string(e.what())); 1752 GPSTK_THROW(strexc); 1753 } 1754 } 1755 1756 /// @todo Need to find a way to combine this with x2d. 1757 // hex to a long. x2uint(const std::string & s)1758 inline unsigned int x2uint(const std::string& s) 1759 { 1760 try 1761 { 1762 // make the stringstream, get the integer, and 1763 // remove it from the string 1764 std::istringstream iss(s); 1765 unsigned int ui; 1766 iss >> std::hex >> ui; 1767 return ui; 1768 } 1769 catch(StringException &e) 1770 { 1771 GPSTK_RETHROW(e); 1772 } 1773 catch(std::exception &e) 1774 { 1775 StringException strexc("Exception thrown: " + std::string(e.what())); 1776 GPSTK_THROW(strexc); 1777 } 1778 } 1779 1780 /// @todo detecting 0 isn't quite right... 1781 // hex to decimal x2d(std::string & s)1782 inline std::string& x2d(std::string& s) 1783 { 1784 try 1785 { 1786 // remove the "0x" part, leading zeros and spaces from the 1787 // string 1788 // ex. ' 0x003' -> '3' 1789 stripLeading(s); 1790 stripLeading(s, "0x", 1); 1791 stripLeading(s, "0"); 1792 1793 // make the stringstream, get the integer, and 1794 // remove it from the string 1795 std::istringstream strstr(s); 1796 int i = 0; 1797 strstr >> std::hex >> i; 1798 stripLeading(s, asString<int>(asInt(s)), 1); 1799 1800 // append the decimal to the existing string 1801 s.insert(0,asString<int>(i)); 1802 return s; 1803 } 1804 catch(StringException &e) 1805 { 1806 GPSTK_RETHROW(e); 1807 } 1808 catch(std::exception &e) 1809 { 1810 StringException strexc("Exception thrown: " + std::string(e.what())); 1811 GPSTK_THROW(strexc); 1812 } 1813 } 1814 int2x(const unsigned int & i)1815 inline std::string int2x(const unsigned int& i) 1816 { 1817 try 1818 { 1819 std::ostringstream ss; 1820 ss << std::hex << i; 1821 return ss.str(); 1822 } 1823 catch(StringException &e) 1824 { 1825 GPSTK_RETHROW(e); 1826 } 1827 catch(std::exception &e) 1828 { 1829 StringException strexc("Exception thrown: " + std::string(e.what())); 1830 GPSTK_THROW(strexc); 1831 } 1832 } 1833 replaceAll(std::string & s,const std::string & oldString,const std::string & newString)1834 inline std::string& replaceAll(std::string& s, 1835 const std::string& oldString, 1836 const std::string& newString) 1837 { 1838 try 1839 { 1840 int spot = s.find(oldString, 0); 1841 while (spot != (int)std::string::npos) 1842 { 1843 s.replace(spot, oldString.length(), newString); 1844 spot += newString.length(); 1845 spot = s.find(oldString, spot); 1846 } 1847 return s; 1848 } 1849 catch(std::exception &e) 1850 { 1851 StringException strexc("Exception thrown: " + std::string(e.what())); 1852 GPSTK_THROW(strexc); 1853 } 1854 } 1855 isDigitString(const std::string & s)1856 inline bool isDigitString(const std::string& s) 1857 { 1858 if (s.size() == 0) 1859 return false; 1860 1861 std::string::size_type index = 0; 1862 if((s[0] == '-') || (s[0] == '+')) 1863 index++; 1864 for( ; index < s.size(); index++) 1865 if (!isdigit(s[index])) 1866 return false; 1867 return true; 1868 } 1869 isDecimalString(const std::string & s)1870 inline bool isDecimalString(const std::string& s) 1871 { 1872 if (s.size() == 0) 1873 return false; 1874 1875 std::string::size_type index = 0; 1876 bool sawdot = false; 1877 if((s[0] == '-') || (s[0] == '+')) 1878 index++; 1879 for( ; index < s.size(); index++) 1880 { 1881 if (s[index] == '.') 1882 { 1883 if (sawdot) 1884 return false; 1885 else sawdot = true; 1886 } 1887 else if (!isdigit(s[index])) 1888 return false; 1889 } 1890 return true; 1891 } 1892 isScientificString(const std::string & s)1893 inline bool isScientificString(const std::string& s) 1894 { 1895 if(s.size() == 0) 1896 return false; 1897 1898 std::string::size_type pos = s.find_first_of("EeDd"); 1899 if(pos == std::string::npos) 1900 return isDecimalString(s); 1901 1902 std::string mant=s.substr(0,pos); 1903 std::string exp=s.substr(pos+1); 1904 return (isDecimalString(mant) && (exp.size()==0 || isDigitString(exp))); 1905 } 1906 isAlphaString(const std::string & s)1907 inline bool isAlphaString(const std::string& s) 1908 { 1909 if (s.size() == 0) 1910 return false; 1911 1912 std::string::size_type index; 1913 for(index = 0; index < s.size(); index++) 1914 if (!isalpha(s[index])) 1915 return false; 1916 return true; 1917 } 1918 matches(const std::string & s,const std::string & aPattern,const char zeroOrMore,const char oneOrMore,const char anyChar)1919 inline std::string matches(const std::string& s, 1920 const std::string& aPattern, 1921 const char zeroOrMore, 1922 const char oneOrMore, 1923 const char anyChar) 1924 { 1925 std::string thisPattern(aPattern); 1926 std::string thisStr(s); 1927 1928 // check if something other than the regex standard 1929 // characters (*,+,.) is used for those variables 1930 if (zeroOrMore != '*') 1931 { 1932 replaceAll(thisPattern, "*", "\\*"); 1933 replaceAll(thisPattern, std::string(1, zeroOrMore), "*"); 1934 } 1935 if (oneOrMore != '+') 1936 { 1937 replaceAll(thisPattern, "+", "\\+"); 1938 replaceAll(thisPattern, std::string(1, oneOrMore), "+"); 1939 } 1940 if (anyChar != '.') 1941 { 1942 replaceAll(thisPattern, ".", "\\."); 1943 replaceAll(thisPattern, std::string(1, anyChar), "."); 1944 } 1945 1946 #if defined(_WIN32) && _MSC_VER >= 1700 1947 try 1948 { 1949 std::regex reg (thisPattern); 1950 1951 std::smatch sm; 1952 if(std::regex_search(thisStr,sm,reg, 1953 std::regex_constants::match_not_bol| 1954 std::regex_constants::match_not_eol)) 1955 { 1956 return sm.str(); 1957 } 1958 else 1959 { 1960 return std::string(); 1961 } 1962 } 1963 catch(std::regex_error& e) 1964 { 1965 Exception E(std::string("std::regex_error: ") + e.what() ); 1966 GPSTK_THROW(E); 1967 } 1968 1969 #else 1970 1971 const std::string::size_type regErrorBufSize = 512; 1972 1973 1974 regmatch_t matches; 1975 regex_t regExp; 1976 char errorMsg[regErrorBufSize]; 1977 int rc = regcomp(®Exp, thisPattern.c_str(), REG_EXTENDED); 1978 1979 if (rc != 0) 1980 { 1981 regerror(rc, NULL, errorMsg, regErrorBufSize - 1); 1982 regfree(®Exp); 1983 StringException strerr("Regexp error: " + std::string(errorMsg)); 1984 GPSTK_THROW(strerr); 1985 } 1986 rc = regexec(®Exp, thisStr.c_str(), 1, &matches, 1987 REG_NOTBOL | REG_NOTEOL); 1988 if ( (rc != 0) && (rc != REG_NOMATCH) ) 1989 { 1990 regerror(rc, ®Exp, errorMsg, regErrorBufSize - 1); 1991 regfree(®Exp); 1992 StringException strerr("Regexp error: " + std::string(errorMsg)); 1993 GPSTK_THROW(strerr); 1994 } 1995 1996 regfree(®Exp); 1997 if (rc == REG_NOMATCH) 1998 return std::string(); 1999 else 2000 return thisStr.substr(matches.rm_so, matches.rm_eo - matches.rm_so); 2001 #endif 2002 } 2003 2004 template <class T> formattedPrint(const std::string & fmt,const std::string & pat,const std::string & rep,T to)2005 inline std::string formattedPrint(const std::string& fmt, 2006 const std::string& pat, 2007 const std::string& rep, 2008 T to) 2009 { 2010 #if defined(_WIN32) && _MSC_VER >= 1700 2011 2012 std::string rv(fmt); 2013 2014 try 2015 { 2016 std::regex reg(pat); 2017 2018 std::smatch m; 2019 while (std::regex_search (rv,m,reg)) 2020 { 2021 std::string mac = m.str(); 2022 mac = StringUtils::replaceAll(mac, rep.substr(0,1), rep.substr(1)); 2023 2024 char buffer[1024]; 2025 sprintf(buffer, mac.c_str(), to); 2026 2027 rv.replace(m.position(), m.length(), std::string(buffer)); 2028 } 2029 } 2030 catch(std::regex_error& e) 2031 { 2032 Exception E(std::string("std::regex_error:")+e.what()); 2033 GPSTK_THROW(E); 2034 } 2035 2036 return rv; 2037 #else 2038 regex_t re; 2039 const size_t bufferSize = 513; 2040 char buffer[bufferSize]; 2041 int rc = regcomp(&re, pat.c_str(), REG_EXTENDED); 2042 // if the regex doesnt compile, toast =) 2043 if ( rc != 0) 2044 { 2045 regerror(rc, NULL, buffer, bufferSize - 1); 2046 regfree(&re); 2047 StringException se("Regexp error: " + std::string(buffer)); 2048 GPSTK_THROW(se); 2049 } 2050 2051 regmatch_t r; 2052 std::string rv = fmt; 2053 2054 while ( regexec(&re, rv.c_str(), 1, &r, 0) == 0 ) 2055 { 2056 size_t len = r.rm_eo - r.rm_so; 2057 std::string mac = rv.substr(r.rm_so, len); 2058 mac = replaceAll(mac, rep.substr(0,1), rep.substr(1)); 2059 sprintf(buffer, mac.c_str(), to); 2060 rv.replace(r.rm_so, len, std::string(buffer)); 2061 } 2062 2063 regfree(&re); 2064 return rv; 2065 #endif 2066 } 2067 subString(const std::string & s,const std::string::size_type startPos,const std::string::size_type length,const char pad)2068 inline std::string subString(const std::string& s, 2069 const std::string::size_type startPos, 2070 const std::string::size_type length, 2071 const char pad) 2072 { 2073 try 2074 { 2075 if(startPos >= s.length()) 2076 { 2077 return std::string(length, pad); 2078 } 2079 std::string temp = s.substr(startPos, length); 2080 return leftJustify(temp, length, pad); 2081 } 2082 catch(StringException &e) 2083 { 2084 GPSTK_RETHROW(e); 2085 } 2086 catch(std::exception &e) 2087 { 2088 StringException strexc("Exception thrown: " + std::string(e.what())); 2089 GPSTK_THROW(strexc); 2090 } 2091 } 2092 lowerCase(std::string & s)2093 inline std::string& lowerCase(std::string& s) 2094 { 2095 for(std::string::size_type i = 0; i < s.length(); i++) 2096 { 2097 s[i] = tolower(s[i]); 2098 } 2099 return s; 2100 } 2101 upperCase(std::string & s)2102 inline std::string& upperCase(std::string& s) 2103 { 2104 for(std::string::size_type i = 0; i < s.length(); i++) 2105 { 2106 s[i] = toupper(s[i]); 2107 } 2108 return s; 2109 } 2110 memToString(const void * p,const std::string::size_type size)2111 inline std::string memToString(const void* p, 2112 const std::string::size_type size) 2113 { 2114 unsigned char* q = (unsigned char*)p; 2115 std::string s(size,'\0'); 2116 for (int i=0; i<(int)size; i++) 2117 { 2118 s[i] = (unsigned char)(*q++); 2119 } 2120 return s; 2121 } 2122 firstWord(const std::string & s,const char delimiter)2123 inline std::string firstWord(const std::string& s, 2124 const char delimiter) 2125 { 2126 try 2127 { 2128 // return s if there are no delimiters 2129 std::string::size_type pos = s.find_first_not_of(delimiter); 2130 if (pos == std::string::npos) 2131 { 2132 return s; 2133 } 2134 // find the end delimiter (if any) and return the string 2135 std::string::size_type endPos = s.find(delimiter, pos); 2136 if (endPos == std::string::npos) 2137 { 2138 return std::string(s, pos, endPos); 2139 } 2140 else 2141 { 2142 return std::string(s, pos, endPos - pos); 2143 } 2144 } 2145 catch(StringException &e) 2146 { 2147 GPSTK_RETHROW(e); 2148 } 2149 catch(std::exception &e) 2150 { 2151 StringException strexc("Exception thrown: " + std::string(e.what())); 2152 GPSTK_THROW(strexc); 2153 } 2154 } 2155 numWords(const std::string & s,const char delimiter)2156 inline int numWords(const std::string& s, 2157 const char delimiter) 2158 { 2159 try 2160 { 2161 std::string t(s); 2162 stripTrailing(t, delimiter); 2163 2164 int words = 0; 2165 while(t.length()) 2166 { 2167 stripLeading(t, delimiter); 2168 stripLeading(t, firstWord(t, delimiter)); 2169 words++; 2170 } 2171 return words; 2172 } 2173 catch(StringException &e) 2174 { 2175 GPSTK_RETHROW(e); 2176 } 2177 catch(std::exception &e) 2178 { 2179 StringException strexc("Exception thrown: " + std::string(e.what())); 2180 GPSTK_THROW(strexc); 2181 } 2182 } 2183 words(const std::string & s,const std::string::size_type firstWord,const std::string::size_type numWords,const char delimiter)2184 inline std::string words(const std::string& s, 2185 const std::string::size_type firstWord, 2186 const std::string::size_type numWords, 2187 const char delimiter) 2188 { 2189 try 2190 { 2191 if ((firstWord == 0) && (numWords == 1)) 2192 return StringUtils::firstWord(s, delimiter); 2193 2194 if (numWords == 0) 2195 return ""; 2196 2197 std::string::size_type wordNum = 0; 2198 std::string::size_type pos = 0, startPos = 0; 2199 2200 std::string toReturn; 2201 2202 // get position of word wordNum 2203 pos = s.find_first_not_of(delimiter, pos); 2204 while ((pos != std::string::npos) && (pos <= s.length())) 2205 { 2206 if (wordNum == firstWord) 2207 startPos = pos; 2208 2209 // get first delimter after word wordNum 2210 pos = s.find(delimiter, pos); 2211 if (((int)numWords != -1) 2212 && ((int)wordNum == (int)(firstWord + (numWords-1)))) 2213 break; 2214 2215 pos = s.find_first_not_of(delimiter, pos); 2216 wordNum++; 2217 } 2218 2219 if (pos == std::string::npos) 2220 return ((wordNum >= firstWord) ? s.substr(startPos) : ""); 2221 2222 return s.substr(startPos, pos-startPos); 2223 } 2224 catch(StringException &e) 2225 { 2226 GPSTK_RETHROW(e); 2227 } 2228 catch(std::exception &e) 2229 { 2230 StringException strexc("Exception thrown: " + std::string(e.what())); 2231 GPSTK_THROW(strexc); 2232 } 2233 } 2234 stripFirstWord(std::string & s,const char delimiter)2235 inline std::string stripFirstWord(std::string& s, 2236 const char delimiter) 2237 { 2238 try 2239 { 2240 stripLeading(s, delimiter); 2241 std::string toReturn = firstWord(s, delimiter); 2242 stripLeading(s, toReturn); 2243 stripLeading(s, delimiter); 2244 return toReturn; 2245 } 2246 catch(StringException &e) 2247 { 2248 GPSTK_RETHROW(e); 2249 } 2250 catch(std::exception &e) 2251 { 2252 StringException strexc("Exception thrown: " + std::string(e.what())); 2253 GPSTK_THROW(strexc); 2254 } 2255 } 2256 split(const std::string & str,const char delimiter)2257 inline std::vector<std::string> split(const std::string& str, 2258 const char delimiter) 2259 { 2260 try { 2261 std::vector<std::string> rvec; // vector to return 2262 std::string tempStr(str); // copy the input string 2263 stripLeading(tempStr,delimiter); // remove leading delimiters 2264 while(tempStr.size() > 0) 2265 rvec.push_back(stripFirstWord(tempStr,delimiter)); 2266 return rvec; 2267 } 2268 catch(StringException &e) 2269 { 2270 GPSTK_RETHROW(e); 2271 } 2272 catch(std::exception &e) 2273 { 2274 StringException strexc("Exception thrown: " + std::string(e.what())); 2275 GPSTK_THROW(strexc); 2276 } 2277 } 2278 split(const std::string & aStr,const std::string & theDelimiters,bool trimWhitespace,bool ignoreEmpty)2279 inline std::vector<std::string> split(const std::string& aStr, 2280 const std::string& theDelimiters, 2281 bool trimWhitespace, 2282 bool ignoreEmpty) 2283 { 2284 std::vector<std::string> toReturn; 2285 2286 std::string::size_type lastPos = aStr.find_first_not_of(theDelimiters, 0); 2287 std::string::size_type pos = aStr.find_first_of(theDelimiters, lastPos); 2288 2289 while (std::string::npos != pos || std::string::npos != lastPos) 2290 { 2291 std::string token = aStr.substr(lastPos, pos - lastPos); 2292 2293 if(trimWhitespace) token = StringUtils::strip(token); 2294 2295 if(!token.empty() || !ignoreEmpty) toReturn.push_back(token); 2296 2297 lastPos = aStr.find_first_not_of(theDelimiters, pos); 2298 pos = aStr.find_first_of(theDelimiters, lastPos); 2299 } 2300 2301 return toReturn; 2302 } 2303 splitWithQuotes(const std::string & aStr,const char delimiter,bool trimWhitespace,bool ignoreEmpty)2304 inline std::vector<std::string> splitWithQuotes(const std::string& aStr, 2305 const char delimiter, 2306 bool trimWhitespace, 2307 bool ignoreEmpty) 2308 { 2309 std::vector<std::string> toReturn; 2310 std::string::size_type begPos = 0; 2311 std::string::size_type endPos = 0; 2312 std::string::size_type tokenLength; 2313 char currentDelimiter; 2314 2315 if(delimiter == '\'' || delimiter == '"') 2316 GPSTK_THROW(StringException("Delimiter must not be quote")); 2317 2318 while(endPos != std::string::npos && endPos <= aStr.length()) 2319 { 2320 currentDelimiter = delimiter; 2321 2322 // if first character is a quote, set current delimiter to it 2323 if(aStr.compare(begPos,1,"\"") == 0) currentDelimiter = '"'; 2324 if(aStr.compare(begPos,1,"\'") == 0) currentDelimiter = '\''; 2325 2326 // find next delimiter 2327 endPos = aStr.find_first_of(currentDelimiter, 2328 begPos + (currentDelimiter == delimiter ? 0 : 1)); 2329 2330 // if this token is quoted, make sure to capture the trailing quote 2331 // if(delimiter is a quote and second quote is found) include it 2332 if(currentDelimiter != delimiter && std::string::npos != endPos) endPos++; 2333 2334 // length of new field 2335 tokenLength = endPos - begPos; 2336 // copy out the field 2337 std::string token = aStr.substr(begPos, tokenLength); 2338 2339 // if quoted, remove the quotes 2340 if(currentDelimiter != delimiter) 2341 token = gpstk::StringUtils::strip(token,currentDelimiter); 2342 2343 // remove whitespace at beginning and end 2344 if(trimWhitespace) token = gpstk::StringUtils::strip(token); 2345 2346 // save it 2347 if(!token.empty() || !ignoreEmpty) toReturn.push_back(token); 2348 2349 // find the next token, and go back to delimiter 2350 begPos = endPos; 2351 if(begPos != std::string::npos) begPos++; 2352 endPos = begPos; 2353 } 2354 2355 return toReturn; 2356 } 2357 splitWithDoubleQuotes(const std::string & aStr,const char delimiter,bool trimWhitespace,bool ignoreEmpty)2358 inline std::vector<std::string> splitWithDoubleQuotes(const std::string& aStr, 2359 const char delimiter, 2360 bool trimWhitespace, 2361 bool ignoreEmpty) 2362 { 2363 std::vector<std::string> toReturn; 2364 std::string::size_type begPos = 0; 2365 std::string::size_type endPos = 0; 2366 std::string::size_type tokenLength; 2367 char currentDelimiter; 2368 2369 if(delimiter == '"') 2370 GPSTK_THROW(StringException("Delimiter must not be quote")); 2371 2372 while(endPos != std::string::npos && endPos <= aStr.length()) 2373 { 2374 currentDelimiter = delimiter; 2375 2376 // if first character is a quote, set current delimiter to it 2377 if(aStr.compare(begPos,1,"\"") == 0) currentDelimiter = '"'; 2378 2379 // find next delimiter 2380 endPos = aStr.find_first_of(currentDelimiter, 2381 begPos + (currentDelimiter == delimiter ? 0 : 1)); 2382 2383 // if this token is quoted, make sure to capture the trailing quote 2384 // if(delimiter is a quote and second quote is found) include it 2385 if(currentDelimiter != delimiter && std::string::npos != endPos) endPos++; 2386 2387 // length of new field 2388 tokenLength = endPos - begPos; 2389 // copy out the field 2390 std::string token = aStr.substr(begPos, tokenLength); 2391 2392 // if quoted, remove the quotes 2393 if(currentDelimiter != delimiter) 2394 token = gpstk::StringUtils::strip(token,currentDelimiter); 2395 2396 // remove whitespace at beginning and end 2397 if(trimWhitespace) token = gpstk::StringUtils::strip(token); 2398 2399 // save it 2400 if(!token.empty() || !ignoreEmpty) toReturn.push_back(token); 2401 2402 // find the next token, and go back to delimiter 2403 begPos = endPos; 2404 if(begPos != std::string::npos) begPos++; 2405 endPos = begPos; 2406 } 2407 2408 return toReturn; 2409 } 2410 removeWords(std::string & s,const std::string::size_type first,const std::string::size_type wordsToReplace,const char delimiter)2411 inline std::string& removeWords(std::string& s, 2412 const std::string::size_type first, 2413 const std::string::size_type wordsToReplace, 2414 const char delimiter) 2415 { 2416 try 2417 { 2418 std::string::size_type rmStart = std::string::npos; 2419 std::string::size_type rmCount = std::string::npos; 2420 2421 // Find start of word 0 2422 std::string::size_type sPos = s.find_first_not_of(delimiter); 2423 2424 for (std::string::size_type thisWord = 0; 2425 sPos != std::string::npos; 2426 thisWord++) 2427 { 2428 // Check for start and end of range to remove 2429 if (thisWord == first) 2430 { 2431 rmStart = sPos; 2432 if (wordsToReplace == std::string::npos) 2433 { 2434 break; 2435 } 2436 } 2437 else if ( (wordsToReplace != std::string::npos) 2438 && (thisWord >= first + wordsToReplace)) 2439 { 2440 rmCount = sPos - rmStart; 2441 break; 2442 } 2443 // Find the end of the current word 2444 sPos = s.find(delimiter, sPos); 2445 if (sPos != std::string::npos) 2446 { 2447 // Find start of next word 2448 sPos = s.find_first_not_of(delimiter, sPos); 2449 } 2450 } 2451 // Remove the words if they were present 2452 if (rmStart != std::string::npos) 2453 { 2454 s.erase(rmStart, rmCount); 2455 if (rmCount == std::string::npos) 2456 { 2457 stripTrailing(s, delimiter); 2458 } 2459 } 2460 return s; 2461 } 2462 catch(StringException &e) 2463 { 2464 GPSTK_RETHROW(e); 2465 } 2466 catch(std::exception &e) 2467 { 2468 StringException strexc("Exception thrown: " + std::string(e.what())); 2469 GPSTK_THROW(strexc); 2470 } 2471 } 2472 doub2sci(const double & d,const std::string::size_type length,const std::string::size_type expLen,const bool showSign,const bool checkSwitch)2473 inline std::string doub2sci(const double& d, 2474 const std::string::size_type length, 2475 const std::string::size_type expLen, 2476 const bool showSign, 2477 const bool checkSwitch) 2478 { 2479 std::string toReturn; 2480 short exponentLength = expLen; 2481 2482 /* Validate the assumptions regarding the input arguments */ 2483 if (exponentLength < 0) exponentLength = 1; 2484 if (exponentLength > 3 && checkSwitch) exponentLength = 3; 2485 2486 std::stringstream c; 2487 c.setf(std::ios::scientific, std::ios::floatfield); 2488 2489 // length - 3 for special characters ('.', 'e', '+' or '-') 2490 // - exponentlength (e04) 2491 // - 1 for the digit before the decimal (2.) 2492 // and if showSign == true, 2493 // an extra -1 for '-' or ' ' if it's positive or negative 2494 int expSize = 0; 2495 if (showSign) 2496 expSize = 1; 2497 c.precision(length - 3 - exponentLength - 1 - expSize); 2498 2499 2500 c << d; 2501 2502 c >> toReturn; 2503 2504 return toReturn; 2505 } 2506 doubleToScientific(const double & d,const std::string::size_type length,const std::string::size_type precision,const std::string::size_type explen,bool showPlus)2507 inline std::string doubleToScientific(const double& d, 2508 const std::string::size_type length, 2509 const std::string::size_type precision, 2510 const std::string::size_type explen, 2511 bool showPlus) 2512 { 2513 // get final exp length, precision and total length 2514 std::string::size_type elen = (explen > 0 ? (explen < 3 ? explen : 3) : 1); 2515 std::string::size_type prec = (precision > 0 ? precision : 1); 2516 std::string::size_type leng = (length > 0 ? length : 1); 2517 2518 // i will be minimum length required with prec==1: force leng if necessary 2519 size_t i = (int(leng) - int(elen) - 4); 2520 if(showPlus) i--; 2521 if(i > 0 && leng < i) leng = std::string::size_type(i); 2522 2523 // set up the stream for writing 2524 std::stringstream ss; 2525 ss << std::scientific << std::setprecision(prec); 2526 if(showPlus) ss << std::showpos; 2527 2528 // write d to a string with precision, sign and in scientific notation 2529 ss << d; 2530 2531 // now read that string 2532 std::string str1,str2; 2533 ss >> str1; 2534 std::string::size_type pos = str1.find_first_of("EDed"); // find exponent 2535 str2 = str1.substr(0,pos+2); // str2 = +123.2345e+ 2536 str1 = str1.substr(pos+2); // str1 = exponent only 2537 2538 // make the exponent length elen 2539 str2 += StringUtils::rightJustify( 2540 StringUtils::asString(StringUtils::asInt(str1)),elen,'0'); 2541 2542 // pad if necessary 2543 if(str2.length() < leng) str2 = StringUtils::rightJustify(str2,leng); 2544 2545 return str2; 2546 } 2547 sci2for(std::string & aStr,const std::string::size_type startPos,const std::string::size_type length,const std::string::size_type expLen,const bool checkSwitch)2548 inline std::string& sci2for(std::string& aStr, 2549 const std::string::size_type startPos, 2550 const std::string::size_type length, 2551 const std::string::size_type expLen, 2552 const bool checkSwitch) 2553 { 2554 try 2555 { 2556 std::string::size_type idx = aStr.find('.', startPos); 2557 int expAdd = 0; 2558 std::string exp; 2559 long iexp; 2560 //If checkSwitch is false, always redo the exponential. Otherwise, 2561 //set it to false. 2562 bool redoexp=!checkSwitch; 2563 2564 // Check for decimal place within specified boundaries 2565 if ((idx == 0) || (idx >= (startPos + length - expLen - 1))) 2566 { 2567 StringException e("sci2for: no decimal point in string"); 2568 GPSTK_THROW(e); 2569 } 2570 2571 // Here, account for the possibility that there are 2572 // no numbers to the left of the decimal, but do not 2573 // account for the possibility of non-scientific 2574 // notation (more than one digit to the left of the 2575 // decimal) 2576 if (idx > startPos) 2577 { 2578 redoexp = true; 2579 // Swap digit and decimal. 2580 aStr[idx] = aStr[idx-1]; 2581 aStr[idx-1] = '.'; 2582 // Only add one to the exponent if the number is non-zero 2583 if (asDouble(aStr.substr(startPos, length)) != 0.0) 2584 expAdd = 1; 2585 } 2586 2587 idx = aStr.find('e', startPos); 2588 if (idx == std::string::npos) 2589 { 2590 idx = aStr.find('E', startPos); 2591 if (idx == std::string::npos) 2592 { 2593 StringException e("sci2for:no 'e' or 'E' in string"); 2594 GPSTK_THROW(e); 2595 } 2596 } 2597 // Change the exponent character to D normally, or E of checkSwitch is false. 2598 if (checkSwitch) 2599 aStr[idx] = 'D'; 2600 else 2601 aStr[idx] = 'E'; 2602 2603 // Change the exponent itself 2604 if (redoexp) 2605 { 2606 exp = aStr.substr(idx + 1, std::string::npos); 2607 iexp = asInt(exp); 2608 iexp += expAdd; 2609 2610 aStr.erase(idx + 1); 2611 if (iexp < 0) 2612 { 2613 aStr += "-"; 2614 iexp -= iexp*2; 2615 } 2616 else 2617 aStr += "+"; 2618 aStr += rightJustify(asString(iexp),expLen,'0'); 2619 2620 } 2621 2622 // if the number is positive, append a space 2623 // (if it's negative, there's a leading '-' 2624 if (aStr[0] == '.') 2625 { 2626 aStr.insert((std::string::size_type)0, 1, ' '); 2627 } 2628 2629 //If checkSwitch is false, add on one leading zero to the string 2630 if (!checkSwitch) 2631 { 2632 aStr.insert((std::string::size_type)1, 1, '0'); 2633 } 2634 2635 2636 return aStr; 2637 } 2638 catch(StringException &e) 2639 { 2640 GPSTK_RETHROW(e); 2641 } 2642 catch(std::exception &e) 2643 { 2644 StringException strexc("Exception thrown: " + std::string(e.what())); 2645 GPSTK_THROW(strexc); 2646 } 2647 } // end sci2for 2648 2649 doub2for(const double & d,const std::string::size_type length,const std::string::size_type expLen,const bool checkSwitch)2650 inline std::string doub2for(const double& d, 2651 const std::string::size_type length, 2652 const std::string::size_type expLen, 2653 const bool checkSwitch) 2654 { 2655 try 2656 { 2657 short exponentLength = expLen; 2658 2659 /* Validate the assumptions regarding the input arguments */ 2660 if (exponentLength < 0) exponentLength = 1; 2661 if (exponentLength > 3 && checkSwitch) exponentLength = 3; 2662 2663 std::string toReturn = doub2sci(d, length, exponentLength, true, checkSwitch); 2664 sci2for(toReturn, 0, length, exponentLength, checkSwitch); 2665 2666 return toReturn; 2667 } 2668 catch(StringException &e) 2669 { 2670 GPSTK_RETHROW(e); 2671 } 2672 catch(std::exception &e) 2673 { 2674 StringException strexc("Exception thrown: " + std::string(e.what())); 2675 GPSTK_THROW(strexc); 2676 } 2677 } 2678 2679 for2doub(const std::string & aStr,const std::string::size_type startPos,const std::string::size_type length)2680 inline double for2doub(const std::string& aStr, 2681 const std::string::size_type startPos, 2682 const std::string::size_type length) 2683 { 2684 std::string s(aStr, startPos, length); 2685 strip(s); 2686 2687 // you can blame Rinex for these special checks 2688 if (s.empty()) 2689 { 2690 return 0; 2691 } 2692 2693 std::string::size_type pos = s.find_first_of("EDd"); 2694 if (pos != std::string::npos) 2695 { 2696 s[pos] = 'e'; 2697 } 2698 else 2699 { 2700 // just treat it like a double 2701 return asDouble(aStr.substr(startPos, length)); 2702 } 2703 2704 std::stringstream st; 2705 st << s; 2706 2707 double d; 2708 st >> d; 2709 2710 return d; 2711 } 2712 printable(const std::string & aStr)2713 inline std::string printable(const std::string& aStr) 2714 { 2715 try 2716 { 2717 std::string rv; 2718 size_t len = aStr.length(); 2719 rv.reserve(len); 2720 2721 for (int i = 0; i < len; i++) 2722 { 2723 char c = aStr[i]; 2724 if (c > 31 && c < 127) // Handle printable ASCII characters 2725 { 2726 rv.append(1,c); 2727 } 2728 else 2729 { 2730 if (c < 0 || c > 127) // Handle non-ASCII characters 2731 { 2732 rv.append("<" + c2x(aStr.substr(i,1)) + ">"); 2733 } 2734 else // Handle control characters 2735 { 2736 char ctrl = (int)c ^ 0x40; // Flip the 7th bit 2737 rv.append(1,'^'); 2738 rv.append(1,ctrl); 2739 } 2740 } 2741 } 2742 2743 return rv; 2744 } 2745 catch(StringException &e) 2746 { 2747 GPSTK_RETHROW(e); 2748 } 2749 catch(std::exception &e) 2750 { 2751 StringException strexc("Exception thrown: " + std::string(e.what())); 2752 GPSTK_THROW(strexc); 2753 } 2754 } 2755 prettyPrint(std::string & aStr,const std::string & lineDelim,const std::string & indent,const std::string & firstIndent,const std::string::size_type len,const char wordDelim)2756 inline std::string& prettyPrint(std::string& aStr, 2757 const std::string& lineDelim, 2758 const std::string& indent, 2759 const std::string& firstIndent, 2760 const std::string::size_type len, 2761 const char wordDelim) 2762 { 2763 try 2764 { 2765 std::string newStr(firstIndent); 2766 // positions of word and line delimiters in aStr 2767 std::string::size_type wordPos = 0, linePos = 0, curPos = 0, 2768 curLineLen = newStr.length(), minPos = 0, wordLen = 0; 2769 bool wordDelimited = false; 2770 while (curPos != std::string::npos) 2771 { 2772 wordPos = aStr.find(wordDelim, curPos); 2773 if (wordPos == curPos) 2774 { 2775 // ignore the word delimeter 2776 curPos++; 2777 continue; 2778 } 2779 // no longer processing a word delimiter 2780 wordDelimited = false; 2781 linePos = aStr.find(lineDelim, curPos); 2782 if (linePos == curPos) 2783 { 2784 curPos += lineDelim.length(); 2785 // line delimiters are NOT compressed. 2786 newStr += lineDelim + indent; 2787 curLineLen = indent.length(); 2788 continue; 2789 } 2790 // add a word 2791 minPos = std::min(wordPos, linePos); 2792 if (minPos != std::string::npos) 2793 wordLen = minPos - curPos; 2794 else 2795 wordLen = aStr.length() - curPos; 2796 if ((curLineLen + wordLen + 1) > len) 2797 { 2798 newStr += lineDelim + indent; 2799 curLineLen = indent.length(); 2800 } 2801 newStr += wordDelim; 2802 newStr += aStr.substr(curPos, wordLen); 2803 curLineLen += wordLen + 1; 2804 curPos = minPos; 2805 } 2806 aStr = newStr + lineDelim; 2807 return aStr; 2808 } 2809 catch (std::exception &e) 2810 { 2811 StringException strexc("Exception thrown: " + 2812 std::string(e.what())); 2813 GPSTK_THROW(strexc); 2814 } 2815 } 2816 2817 //@} 2818 2819 } // namespace StringUtils 2820 2821 } // namespace gpstk 2822 #endif // GPSTK_STRINGUTILS_HPP 2823