moneystr.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto 2 // Copyright (c) 2009-present The Bitcoin Core developers 3 // Distributed under the MIT software license, see the accompanying 4 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 6 #include <util/moneystr.h> 7 8 #include <consensus/amount.h> 9 #include <tinyformat.h> 10 #include <util/strencodings.h> 11 #include <util/string.h> 12 13 #include <cstdint> 14 #include <optional> 15 16 using util::ContainsNoNUL; 17 using util::TrimString; 18 19 std::string FormatMoney(const CAmount n) 20 { 21 // Note: not using straight sprintf here because we do NOT want 22 // localized number formatting. 23 static_assert(COIN > 1); 24 int64_t quotient = n / COIN; 25 int64_t remainder = n % COIN; 26 if (n < 0) { 27 quotient = -quotient; 28 remainder = -remainder; 29 } 30 std::string str = strprintf("%d.%08d", quotient, remainder); 31 32 // Right-trim excess zeros before the decimal point: 33 int nTrim = 0; 34 for (int i = str.size()-1; (str[i] == '0' && IsDigit(str[i-2])); --i) 35 ++nTrim; 36 if (nTrim) 37 str.erase(str.size()-nTrim, nTrim); 38 39 if (n < 0) 40 str.insert(uint32_t{0}, 1, '-'); 41 return str; 42 } 43 44 45 std::optional<CAmount> ParseMoney(const std::string& money_string) 46 { 47 if (!ContainsNoNUL(money_string)) { 48 return std::nullopt; 49 } 50 const std::string str = TrimString(money_string); 51 if (str.empty()) { 52 return std::nullopt; 53 } 54 55 std::string strWhole; 56 int64_t nUnits = 0; 57 const char* p = str.c_str(); 58 for (; *p; p++) 59 { 60 if (*p == '.') 61 { 62 p++; 63 int64_t nMult = COIN / 10; 64 while (IsDigit(*p) && (nMult > 0)) 65 { 66 nUnits += nMult * (*p++ - '0'); 67 nMult /= 10; 68 } 69 break; 70 } 71 if (IsSpace(*p)) 72 return std::nullopt; 73 if (!IsDigit(*p)) 74 return std::nullopt; 75 strWhole.insert(strWhole.end(), *p); 76 } 77 if (*p) { 78 return std::nullopt; 79 } 80 if (strWhole.size() > 10) // guard against 63 bit overflow 81 return std::nullopt; 82 if (nUnits < 0 || nUnits > COIN) 83 return std::nullopt; 84 int64_t nWhole = LocaleIndependentAtoi<int64_t>(strWhole); 85 CAmount value = nWhole * COIN + nUnits; 86 87 if (!MoneyRange(value)) { 88 return std::nullopt; 89 } 90 91 return value; 92 }