Overhaul of the temp_folder() function + use scoped pointers for global objects.
[MUtilities.git] / src / Global.cpp
blobb56043275557fa32cb841a43ca6212d2daa452c4
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
22 #if _MSC_VER
23 #define _CRT_RAND_S 1
24 #endif
26 #include <MUtils/Global.h>
27 #include <MUtils/OSSupport.h>
29 //Qt
30 #include <QDir>
31 #include <QReadWriteLock>
32 #include <QProcess>
34 //CRT
35 #include <cstdlib>
36 #include <ctime>
37 #include <process.h>
39 ///////////////////////////////////////////////////////////////////////////////
40 // Random Support
41 ///////////////////////////////////////////////////////////////////////////////
43 //Robert Jenkins' 96 bit Mix Function
44 static unsigned int mix_function(const unsigned int x, const unsigned int y, const unsigned int z)
46 unsigned int a = x;
47 unsigned int b = y;
48 unsigned int c = z;
50 a=a-b; a=a-c; a=a^(c >> 13);
51 b=b-c; b=b-a; b=b^(a << 8 );
52 c=c-a; c=c-b; c=c^(b >> 13);
53 a=a-b; a=a-c; a=a^(c >> 12);
54 b=b-c; b=b-a; b=b^(a << 16);
55 c=c-a; c=c-b; c=c^(b >> 5 );
56 a=a-b; a=a-c; a=a^(c >> 3 );
57 b=b-c; b=b-a; b=b^(a << 10);
58 c=c-a; c=c-b; c=c^(b >> 15);
60 return a ^ b ^ c;
63 void MUtils::seed_rand(void)
65 qsrand(mix_function(clock(), time(NULL), _getpid()));
68 quint32 MUtils::next_rand32(void)
70 quint32 rnd = 0xDEADBEEF;
72 #ifdef _CRT_RAND_S
73 if(rand_s(&rnd) == 0)
75 return rnd;
77 #endif //_CRT_RAND_S
79 for(size_t i = 0; i < sizeof(quint32); i++)
81 rnd = (rnd << 8) ^ qrand();
84 return rnd;
87 quint64 MUtils::next_rand64(void)
89 return (quint64(next_rand32()) << 32) | quint64(next_rand32());
92 QString MUtils::rand_str(const bool &bLong)
94 if(!bLong)
96 return QString::number(next_rand64(), 16).rightJustified(16, QLatin1Char('0'));
98 return QString("%1%2").arg(rand_str(false), rand_str(false));
101 ///////////////////////////////////////////////////////////////////////////////
102 // TEMP FOLDER
103 ///////////////////////////////////////////////////////////////////////////////
105 static QScopedPointer<QFile> g_temp_folder_file;
106 static QScopedPointer<QString> g_temp_folder_path;
107 static QReadWriteLock g_temp_folder_lock;
109 static QString try_create_subfolder(const QString &baseDir, const QString &postfix)
111 const QString baseDirPath = QDir(baseDir).absolutePath();
112 for(int i = 0; i < 32; i++)
114 QDir directory(baseDirPath);
115 if(directory.mkpath(postfix) && directory.cd(postfix))
117 return directory.canonicalPath();
120 return QString();
123 static QString try_init_temp_folder(const QString &baseDir)
125 static const char *TEST_DATA = "Lorem ipsum dolor sit amet, consectetur, adipisci velit!";
127 QString tempPath = try_create_subfolder(baseDir, MUtils::rand_str());
128 if(!tempPath.isEmpty())
130 const QByteArray testData = QByteArray(TEST_DATA);
131 for(int i = 0; i < 32; i++)
133 g_temp_folder_file.reset(new QFile(QString("%1/~%2.lck").arg(tempPath, MUtils::rand_str())));
134 if(g_temp_folder_file->open(QIODevice::ReadWrite | QIODevice::Truncate))
136 if(g_temp_folder_file->write(testData) >= testData.size())
138 return tempPath;
140 g_temp_folder_file->remove();
145 return QString();
148 const QString &MUtils::temp_folder(void)
150 QReadLocker readLock(&g_temp_folder_lock);
152 //Already initialized?
153 if((!g_temp_folder_path.isNull()) && (!g_temp_folder_path->isEmpty()))
155 return (*g_temp_folder_path.data());
158 //Obtain the write lock to initilaize
159 readLock.unlock();
160 QWriteLocker writeLock(&g_temp_folder_lock);
162 //Still uninitilaized?
163 if((!g_temp_folder_path.isNull()) && (!g_temp_folder_path->isEmpty()))
165 return (*g_temp_folder_path.data());
168 //Try the %TMP% or %TEMP% directory first
169 QString tempPath = try_init_temp_folder(QDir::tempPath());
170 if(!tempPath.isEmpty())
172 g_temp_folder_path.reset(new QString(tempPath));
173 return (*g_temp_folder_path.data());
176 qWarning("%%TEMP%% directory not found -> trying fallback mode now!");
177 static const OS::known_folder_t FOLDER_ID[2] = { OS::FOLDER_LOCALAPPDATA, OS::FOLDER_SYSTROOT_DIR };
178 for(size_t id = 0; id < 2; id++)
180 const QString &knownFolder = OS::known_folder(FOLDER_ID[id]);
181 if(!knownFolder.isEmpty())
183 const QString tempRoot = try_create_subfolder(knownFolder, QLatin1String("TEMP"));
184 if(!tempRoot.isEmpty())
186 tempPath = try_init_temp_folder(tempRoot);
187 if(!tempPath.isEmpty())
189 g_temp_folder_path.reset(new QString(tempPath));
190 return (*g_temp_folder_path.data());
196 qFatal("Temporary directory could not be initialized !!!");
197 return (*((QString*)NULL));
200 ///////////////////////////////////////////////////////////////////////////////
201 // PROCESS UTILS
202 ///////////////////////////////////////////////////////////////////////////////
204 void MUtils::init_process(QProcess &process, const QString &wokringDir, const bool bReplaceTempDir)
206 //Environment variable names
207 static const char *const s_envvar_names_temp[] =
209 "TEMP", "TMP", "TMPDIR", "HOME", "USERPROFILE", "HOMEPATH", NULL
211 static const char *const s_envvar_names_remove[] =
213 "WGETRC", "SYSTEM_WGETRC", "HTTP_PROXY", "FTP_PROXY", "NO_PROXY", "GNUPGHOME", "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LANG", NULL
216 //Initialize environment
217 QProcessEnvironment env = process.processEnvironment();
218 if(env.isEmpty()) env = QProcessEnvironment::systemEnvironment();
220 //Clean a number of enviroment variables that might affect our tools
221 for(size_t i = 0; s_envvar_names_remove[i]; i++)
223 env.remove(QString::fromLatin1(s_envvar_names_remove[i]));
224 env.remove(QString::fromLatin1(s_envvar_names_remove[i]).toLower());
227 const QString tempDir = QDir::toNativeSeparators(temp_folder());
229 //Replace TEMP directory in environment
230 if(bReplaceTempDir)
232 for(size_t i = 0; s_envvar_names_temp[i]; i++)
234 env.insert(s_envvar_names_temp[i], tempDir);
238 //Setup PATH variable
239 const QString path = env.value("PATH", QString()).trimmed();
240 env.insert("PATH", path.isEmpty() ? tempDir : QString("%1;%2").arg(tempDir, path));
242 //Setup QPorcess object
243 process.setWorkingDirectory(wokringDir);
244 process.setProcessChannelMode(QProcess::MergedChannels);
245 process.setReadChannel(QProcess::StandardOutput);
246 process.setProcessEnvironment(env);
249 ///////////////////////////////////////////////////////////////////////////////
250 // LIB VERSION
251 ///////////////////////////////////////////////////////////////////////////////
253 const char* MUtils::mutils_build_date(void)
255 static const char *const BUILD_DATE = __DATE__;
256 return BUILD_DATE;
259 const char* MUtils::mutils_build_time(void)
261 static const char *const BUILD_TIME = __TIME__;
262 return BUILD_TIME;
265 ///////////////////////////////////////////////////////////////////////////////
266 // SELF-TEST
267 ///////////////////////////////////////////////////////////////////////////////
269 int MUtils::Internal::selfTest(const char *const date, const bool debug)
271 if(strcmp(date, __DATE__) || (MUTILS_DEBUG != debug))
273 MUtils::OS::system_message_err(L"MUtils", L"FATAL ERROR: MUtils library version mismatch detected!");
274 abort();
276 return 0;