Better wording for transaction fee notification messages
[novacoin.git] / util.cpp
index 2cfd560..2359616 100644 (file)
--- a/util.cpp
+++ b/util.cpp
@@ -11,11 +11,15 @@ bool fDebug = false;
 bool fPrintToConsole = false;
 bool fPrintToDebugger = false;
 char pszSetDataDir[MAX_PATH] = "";
+bool fRequestShutdown = false;
 bool fShutdown = false;
 bool fDaemon = false;
+bool fServer = false;
 bool fCommandLine = false;
-string strWarning;
-
+string strMiscWarning;
+bool fTestNet = false;
+bool fNoListen = false;
+bool fLogTimestamps = false;
 
 
 
@@ -79,7 +83,7 @@ instance_of_cinit;
 void RandAddSeed()
 {
     // Seed with CPU performance counter
-    int64 nCounter = PerformanceCounter();
+    int64 nCounter = GetPerformanceCounter();
     RAND_add(&nCounter, sizeof(nCounter), 1.5);
     memset(&nCounter, 0, sizeof(nCounter));
 }
@@ -104,12 +108,8 @@ void RandAddSeedPerfmon()
     RegCloseKey(HKEY_PERFORMANCE_DATA);
     if (ret == ERROR_SUCCESS)
     {
-        uint256 hash;
-        SHA256(pdata, nSize, (unsigned char*)&hash);
-        RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));
-        hash = 0;
+        RAND_add(pdata, nSize, nSize/100.0);
         memset(pdata, 0, nSize);
-
         printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize);
     }
 #endif
@@ -130,6 +130,11 @@ uint64 GetRand(uint64 nMax)
     return (nRand % nMax);
 }
 
+int GetRandInt(int nMax)
+{
+    return GetRand(nMax);
+}
+
 
 
 
@@ -154,27 +159,41 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
     else
     {
         // print to debug.log
-        char pszFile[MAX_PATH+100];
-        GetDataDir(pszFile);
-        strlcat(pszFile, "/debug.log", sizeof(pszFile));
-        FILE* fileout = fopen(pszFile, "a");
+        static FILE* fileout = NULL;
+
+        if (!fileout)
+        {
+            char pszFile[MAX_PATH+100];
+            GetDataDir(pszFile);
+            strlcat(pszFile, "/debug.log", sizeof(pszFile));
+            fileout = fopen(pszFile, "a");
+            if (fileout) setbuf(fileout, NULL); // unbuffered
+        }
         if (fileout)
         {
-            //// Debug print useful for profiling
-            //fprintf(fileout, " %"PRI64d" ", GetTimeMillis());
+            static bool fStartedNewLine = true;
+
+            // Debug print useful for profiling
+            if (fLogTimestamps && fStartedNewLine)
+                fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+            if (pszFormat[strlen(pszFormat) - 1] == '\n')
+                fStartedNewLine = true;
+            else
+                fStartedNewLine = false;
+
             va_list arg_ptr;
             va_start(arg_ptr, pszFormat);
             ret = vfprintf(fileout, pszFormat, arg_ptr);
             va_end(arg_ptr);
-            fclose(fileout);
         }
     }
 
 #ifdef __WXMSW__
     if (fPrintToDebugger)
     {
-        // accumulate a line at a time
         static CCriticalSection cs_OutputDebugStringF;
+
+        // accumulate a line at a time
         CRITICAL_BLOCK(cs_OutputDebugStringF)
         {
             static char pszBuffer[50000];
@@ -304,9 +323,23 @@ void ParseString(const string& str, char c, vector<string>& v)
 
 string FormatMoney(int64 n, bool fPlus)
 {
-    n /= CENT;
-    string str = strprintf("%"PRI64d".%02"PRI64d, (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100);
-    for (int i = 6; i < str.size(); i += 4)
+    // Note: not using straight sprintf here because we do NOT want
+    // localized number formatting.
+    int64 n_abs = (n > 0 ? n : -n);
+    int64 quotient = n_abs/COIN;
+    int64 remainder = n_abs%COIN;
+    string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder);
+
+    // Right-trim excess 0's before the decimal point:
+    int nTrim = 0;
+    for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)
+        ++nTrim;
+    if (nTrim)
+        str.erase(str.size()-nTrim, nTrim);
+
+    // Insert thousands-separators:
+    size_t point = str.find(".");
+    for (int i = (str.size()-point)+3; i < str.size(); i += 4)
         if (isdigit(str[str.size() - i - 1]))
             str.insert(str.size() - i, 1, ',');
     if (n < 0)
@@ -325,7 +358,7 @@ bool ParseMoney(const string& str, int64& nRet)
 bool ParseMoney(const char* pszIn, int64& nRet)
 {
     string strWhole;
-    int64 nCents = 0;
+    int64 nUnits = 0;
     const char* p = pszIn;
     while (isspace(*p))
         p++;
@@ -336,11 +369,11 @@ bool ParseMoney(const char* pszIn, int64& nRet)
         if (*p == '.')
         {
             p++;
-            if (isdigit(*p))
+            int64 nMult = CENT*10;
+            while (isdigit(*p) && (nMult > 0))
             {
-                nCents = 10 * (*p++ - '0');
-                if (isdigit(*p))
-                    nCents += (*p++ - '0');
+                nUnits += nMult * (*p++ - '0');
+                nMult /= 10;
             }
             break;
         }
@@ -355,15 +388,11 @@ bool ParseMoney(const char* pszIn, int64& nRet)
             return false;
     if (strWhole.size() > 14)
         return false;
-    if (nCents < 0 || nCents > 99)
+    if (nUnits < 0 || nUnits > COIN)
         return false;
     int64 nWhole = atoi64(strWhole);
-    int64 nPreValue = nWhole * 100 + nCents;
-    int64 nValue = nPreValue * CENT;
-    if (nValue / CENT != nPreValue)
-        return false;
-    if (nValue / COIN != nWhole)
-        return false;
+    int64 nValue = nWhole*COIN + nUnits;
+
     nRet = nValue;
     return true;
 }
@@ -371,11 +400,6 @@ bool ParseMoney(const char* pszIn, int64& nRet)
 
 vector<unsigned char> ParseHex(const char* psz)
 {
-    vector<unsigned char> vch;
-    while (isspace(*psz))
-        psz++;
-    vch.reserve((strlen(psz)+1)/3);
-
     static char phexdigit[256] =
     { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
@@ -394,28 +418,26 @@ vector<unsigned char> ParseHex(const char* psz)
       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
 
-    while (*psz)
+    // convert hex dump to vector
+    vector<unsigned char> vch;
+    loop
     {
+        while (isspace(*psz))
+            psz++;
         char c = phexdigit[(unsigned char)*psz++];
-        if (c == -1)
+        if (c == (char)-1)
             break;
         unsigned char n = (c << 4);
-        if (*psz)
-        {
-            char c = phexdigit[(unsigned char)*psz++];
-            if (c == -1)
-                break;
-            n |= c;
-            vch.push_back(n);
-        }
-        while (isspace(*psz))
-            psz++;
+        c = phexdigit[(unsigned char)*psz++];
+        if (c == (char)-1)
+            break;
+        n |= c;
+        vch.push_back(n);
     }
-
     return vch;
 }
 
-vector<unsigned char> ParseHex(const std::string& str)
+vector<unsigned char> ParseHex(const string& str)
 {
     return ParseHex(str.c_str());
 }
@@ -483,6 +505,34 @@ const char* wxGetTranslation(const char* pszEnglish)
 }
 
 
+bool WildcardMatch(const char* psz, const char* mask)
+{
+    loop
+    {
+        switch (*mask)
+        {
+        case '\0':
+            return (*psz == '\0');
+        case '*':
+            return WildcardMatch(psz, mask+1) || (*psz && WildcardMatch(psz+1, mask));
+        case '?':
+            if (*psz == '\0')
+                return false;
+            break;
+        default:
+            if (*psz != *mask)
+                return false;
+            break;
+        }
+        psz++;
+        mask++;
+    }
+}
+
+bool WildcardMatch(const string& str, const string& mask)
+{
+    return WildcardMatch(str.c_str(), mask.c_str());
+}
 
 
 
@@ -510,23 +560,47 @@ void FormatException(char* pszMessage, std::exception* pex, const char* pszThrea
 
 void LogException(std::exception* pex, const char* pszThread)
 {
-    char pszMessage[1000];
+    char pszMessage[10000];
     FormatException(pszMessage, pex, pszThread);
     printf("\n%s", pszMessage);
 }
 
 void PrintException(std::exception* pex, const char* pszThread)
 {
-    char pszMessage[1000];
+    char pszMessage[10000];
     FormatException(pszMessage, pex, pszThread);
     printf("\n\n************************\n%s\n", pszMessage);
     fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
+    strMiscWarning = pszMessage;
 #ifdef GUI
     if (wxTheApp && !fDaemon)
-        MyMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);
+        MyMessageBox(pszMessage, "Bitcoin", wxOK | wxICON_ERROR);
 #endif
     throw;
-    //DebugBreak();
+}
+
+void ThreadOneMessageBox(string strMessage)
+{
+    // Skip message boxes if one is already open
+    static bool fMessageBoxOpen;
+    if (fMessageBoxOpen)
+        return;
+    fMessageBoxOpen = true;
+    ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
+    fMessageBoxOpen = false;
+}
+
+void PrintExceptionContinue(std::exception* pex, const char* pszThread)
+{
+    char pszMessage[10000];
+    FormatException(pszMessage, pex, pszThread);
+    printf("\n\n************************\n%s\n", pszMessage);
+    fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
+    strMiscWarning = pszMessage;
+#ifdef GUI
+    if (wxTheApp && !fDaemon)
+        boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
+#endif
 }
 
 
@@ -602,15 +676,11 @@ string GetDefaultDataDir()
 void GetDataDir(char* pszDir)
 {
     // pszDir must be at least MAX_PATH length.
+    int nVariation;
     if (pszSetDataDir[0] != 0)
     {
         strlcpy(pszDir, pszSetDataDir, MAX_PATH);
-        static bool fMkdirDone;
-        if (!fMkdirDone)
-        {
-            fMkdirDone = true;
-            filesystem::create_directory(pszDir);
-        }
+        nVariation = 0;
     }
     else
     {
@@ -618,11 +688,23 @@ void GetDataDir(char* pszDir)
         // value so we don't have to do memory allocations after that.
         static char pszCachedDir[MAX_PATH];
         if (pszCachedDir[0] == 0)
-        {
             strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
-            filesystem::create_directory(pszCachedDir);
-        }
         strlcpy(pszDir, pszCachedDir, MAX_PATH);
+        nVariation = 1;
+    }
+    if (fTestNet)
+    {
+        char* p = pszDir + strlen(pszDir);
+        if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
+            *p++ = '/';
+        strcpy(p, "testnet");
+        nVariation += 2;
+    }
+    static bool pfMkdir[4];
+    if (!pfMkdir[nVariation])
+    {
+        pfMkdir[nVariation] = true;
+        filesystem::create_directory(pszDir);
     }
 }
 
@@ -636,7 +718,7 @@ string GetDataDir()
 string GetConfigFile()
 {
     namespace fs = boost::filesystem;
-    fs::path pathConfig(mapArgs.count("-conf") ? mapArgs["-conf"] : string("bitcoin.conf"));
+    fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
     if (!pathConfig.is_complete())
         pathConfig = fs::path(GetDataDir()) / pathConfig;
     return pathConfig.string();
@@ -665,6 +747,25 @@ void ReadConfigFile(map<string, string>& mapSettingsRet,
     }
 }
 
+string GetPidFile()
+{
+    namespace fs = boost::filesystem;
+    fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
+    if (!pathConfig.is_complete())
+        pathConfig = fs::path(GetDataDir()) / pathConfig;
+    return pathConfig.string();
+}
+
+void CreatePidFile(string pidFile, pid_t pid)
+{
+    FILE* file;
+    if (file = fopen(pidFile.c_str(), "w"))
+    {
+        fprintf(file, "%d\n", pid);
+        fclose(file);
+    }
+}
+
 int GetFilesize(FILE* file)
 {
     int nSavePos = ftell(file);
@@ -704,13 +805,10 @@ void ShrinkDebugFile()
 
 //
 // "Never go to sea with two chronometers; take one or three."
-// Our three chronometers are:
+// Our three time sources are:
 //  - System clock
-//  - Median of other server's clocks
-//  - NTP servers
-//
-// note: NTP isn't implemented yet, so until then we just use the median
-//  of other nodes clocks to correct ours.
+//  - Median of other nodes's clocks
+//  - The user (asking the user to fix the system clock if the first two disagree)
 //
 int64 GetTime()
 {
@@ -751,19 +849,24 @@ void AddTimeData(unsigned int ip, int64 nTime)
         else
         {
             nTimeOffset = 0;
-            // If nobody else has the same time as us, give a warning
-            bool fMatch = false;
-            foreach(int64 nOffset, vTimeOffsets)
-                if (nOffset != 0 && abs64(nOffset) < 10 * 60)
-                    fMatch = true;
+
             static bool fDone;
-            if (!fMatch && !fDone)
+            if (!fDone)
             {
-                fDone = true;
-                string strMessage = _("Warning: Check your system date and time, you may not be able to generate or receive the most recent blocks!");
-                strWarning = strMessage;
-                printf("*** %s\n", strMessage.c_str());
-                boost::thread(bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
+                // If nobody has a time different than ours but within 5 minutes of ours, give a warning
+                bool fMatch = false;
+                foreach(int64 nOffset, vTimeOffsets)
+                    if (nOffset != 0 && abs64(nOffset) < 5 * 60)
+                        fMatch = true;
+
+                if (!fMatch)
+                {
+                    fDone = true;
+                    string strMessage = _("Warning: Please check that your computer's date and time are correct.  If your clock is wrong Bitcoin will not work properly.");
+                    strMiscWarning = strMessage;
+                    printf("*** %s\n", strMessage.c_str());
+                    boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
+                }
             }
         }
         foreach(int64 n, vTimeOffsets)
@@ -771,3 +874,32 @@ void AddTimeData(unsigned int ip, int64 nTime)
         printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
     }
 }
+
+
+
+
+
+
+
+
+
+string FormatVersion(int nVersion)
+{
+    if (nVersion%100 == 0)
+        return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100);
+    else
+        return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100);
+}
+
+string FormatFullVersion()
+{
+    string s = FormatVersion(VERSION) + pszSubVer;
+    if (VERSION_IS_BETA)
+        s += _("-beta");
+    return s;
+}
+
+
+
+
+