Some improvements to library initialization code.
[MUtilities.git] / src / Global.cpp
blobda1dc7d460afb43c8ab897cffa6c787855acfa3f
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2019 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 //MUtils
27 #include <MUtils/Global.h>
28 #include <MUtils/OSSupport.h>
29 #include <MUtils/Version.h>
30 #include "Internal.h"
32 //Internal
33 #include "DirLocker.h"
34 #include "3rd_party/strnatcmp/include/strnatcmp.h"
36 //Qt
37 #include <QDir>
38 #include <QReadWriteLock>
39 #include <QProcess>
40 #include <QTextCodec>
41 #include <QPair>
42 #include <QHash>
43 #include <QListIterator>
44 #include <QMutex>
45 #include <QThreadStorage>
47 //CRT
48 #include <cstdlib>
49 #include <ctime>
50 #include <process.h>
52 //VLD
53 #ifdef _MSC_VER
54 #include <vld.h>
55 #endif
57 //Global
58 const QString MUtils::Internal::g_empty;
60 ///////////////////////////////////////////////////////////////////////////////
61 // Random Support
62 ///////////////////////////////////////////////////////////////////////////////
64 #ifndef _CRT_RAND_S
65 #define rand_s(X) (true)
66 #endif
68 //Per-thread init flag
69 static QThreadStorage<bool> g_srand_flag;
71 //32-Bit wrapper for qrand()
72 #define QRAND() ((static_cast<quint32>(qrand()) & 0xFFFF) | (static_cast<quint32>(qrand()) << 16U))
74 //Robert Jenkins' 96 bit Mix Function
75 static quint32 mix_function(quint32 a, quint32 b, quint32 c)
77 a=a-b; a=a-c; a=a^(c >> 13);
78 b=b-c; b=b-a; b=b^(a << 8);
79 c=c-a; c=c-b; c=c^(b >> 13);
80 a=a-b; a=a-c; a=a^(c >> 12);
81 b=b-c; b=b-a; b=b^(a << 16);
82 c=c-a; c=c-b; c=c^(b >> 5);
83 a=a-b; a=a-c; a=a^(c >> 3);
84 b=b-c; b=b-a; b=b^(a << 10);
85 c=c-a; c=c-b; c=c^(b >> 15);
87 return a ^ b ^ c;
90 static void seed_rand(void)
92 QDateTime build(MUtils::Version::lib_build_date(), MUtils::Version::lib_build_time());
93 const quint32 seed_0 = mix_function(MUtils::OS::process_id(), MUtils::OS::thread_id(), build.toMSecsSinceEpoch());
94 qsrand(mix_function(clock(), time(NULL), seed_0));
97 static quint32 rand_fallback(void)
99 Q_ASSERT(RAND_MAX >= 0x7FFF);
101 if (!(g_srand_flag.hasLocalData() && g_srand_flag.localData()))
103 seed_rand();
104 g_srand_flag.setLocalData(true);
107 quint32 rnd_val = mix_function(0x32288EA3, clock(), time(NULL));
109 for (size_t i = 0; i < 42; i++)
111 rnd_val = mix_function(rnd_val, QRAND(), QRAND());
112 rnd_val = mix_function(QRAND(), rnd_val, QRAND());
113 rnd_val = mix_function(QRAND(), QRAND(), rnd_val);
116 return rnd_val;
119 quint32 MUtils::next_rand_u32(void)
121 quint32 rnd;
122 if (rand_s(&rnd))
124 return rand_fallback();
126 return rnd;
129 quint32 MUtils::next_rand_u32(const quint32 max)
131 static const uint32_t DIV_LUT[64] =
133 0xFFFFFFFF, 0xFFFFFFFF, 0x80000000, 0x55555556, 0x40000000, 0x33333334, 0x2AAAAAAB, 0x24924925,
134 0x20000000, 0x1C71C71D, 0x1999999A, 0x1745D175, 0x15555556, 0x13B13B14, 0x12492493, 0x11111112,
135 0x10000000, 0x0F0F0F10, 0x0E38E38F, 0x0D79435F, 0x0CCCCCCD, 0x0C30C30D, 0x0BA2E8BB, 0x0B21642D,
136 0x0AAAAAAB, 0x0A3D70A4, 0x09D89D8A, 0x097B425F, 0x0924924A, 0x08D3DCB1, 0x08888889, 0x08421085,
137 0x08000000, 0x07C1F07D, 0x07878788, 0x07507508, 0x071C71C8, 0x06EB3E46, 0x06BCA1B0, 0x06906907,
138 0x06666667, 0x063E7064, 0x06186187, 0x05F417D1, 0x05D1745E, 0x05B05B06, 0x0590B217, 0x0572620B,
139 0x05555556, 0x0539782A, 0x051EB852, 0x05050506, 0x04EC4EC5, 0x04D4873F, 0x04BDA130, 0x04A7904B,
140 0x04924925, 0x047DC120, 0x0469EE59, 0x0456C798, 0x04444445, 0x04325C54, 0x04210843, 0x04104105
142 return (max < 64) ? (next_rand_u32() / DIV_LUT[max]) : (next_rand_u32() / (UINT32_MAX / max + 1U));
146 quint64 MUtils::next_rand_u64(void)
148 return (quint64(next_rand_u32()) << 32) | quint64(next_rand_u32());
151 QString MUtils::next_rand_str(const bool &bLong)
153 if (bLong)
155 return next_rand_str(false) + next_rand_str(false);
157 else
159 return QString::number(next_rand_u64(), 16).rightJustified(16, QLatin1Char('0'));
163 ///////////////////////////////////////////////////////////////////////////////
164 // STRING UTILITY FUNCTIONS
165 ///////////////////////////////////////////////////////////////////////////////
167 static QScopedPointer<QRegExp> g_str_trim_rx_r;
168 static QScopedPointer<QRegExp> g_str_trim_rx_l;
169 static QMutex g_str_trim_lock;
171 static QString& trim_helper(QString &str, QScopedPointer<QRegExp> &regex, const char *const pattern)
173 QMutexLocker lock(&g_str_trim_lock);
174 if (regex.isNull())
176 regex.reset(new QRegExp(QLatin1String(pattern)));
178 str.remove(*regex.data());
179 return str;
182 QString& MUtils::trim_right(QString &str)
184 static const char *const TRIM_RIGHT = "\\s+$";
185 return trim_helper(str, g_str_trim_rx_r, TRIM_RIGHT);
188 QString& MUtils::trim_left(QString &str)
190 static const char *const TRIM_LEFT = "^\\s+";
191 return trim_helper(str, g_str_trim_rx_l, TRIM_LEFT);
194 QString MUtils::trim_right(const QString &str)
196 QString temp(str);
197 return trim_right(temp);
200 QString MUtils::trim_left(const QString &str)
202 QString temp(str);
203 return trim_left(temp);
206 ///////////////////////////////////////////////////////////////////////////////
207 // GENERATE FILE NAME
208 ///////////////////////////////////////////////////////////////////////////////
210 QString MUtils::make_temp_file(const QString &basePath, const QString &extension, const bool placeholder)
212 return make_temp_file(QDir(basePath), extension, placeholder);
215 QString MUtils::make_temp_file(const QDir &basePath, const QString &extension, const bool placeholder)
217 if (extension.isEmpty())
219 qWarning("Cannot generate temp file name with invalid parameters!");
220 return QString();
223 for(int i = 0; i < 4096; i++)
225 const QString tempFileName = basePath.absoluteFilePath(QString("%1.%2").arg(next_rand_str(), extension));
226 if(!QFileInfo(tempFileName).exists())
228 if(placeholder)
230 QFile file(tempFileName);
231 if(file.open(QFile::ReadWrite))
233 file.close();
234 return tempFileName;
237 else
239 return tempFileName;
244 qWarning("Failed to generate temp file name!");
245 return QString();
248 QString MUtils::make_unique_file(const QString &basePath, const QString &baseName, const QString &extension, const bool fancy, const bool placeholder)
250 return make_unique_file(QDir(basePath), baseName, extension, fancy);
253 QString MUtils::make_unique_file(const QDir &basePath, const QString &baseName, const QString &extension, const bool fancy, const bool placeholder)
255 if (baseName.isEmpty() || extension.isEmpty())
257 qWarning("Cannot generate unique file name with invalid parameters!");
258 return QString();
261 quint32 n = fancy ? 2 : 0;
262 QString fileName = fancy ? basePath.absoluteFilePath(QString("%1.%2").arg(baseName, extension)) : QString();
263 while (fileName.isEmpty() || QFileInfo(fileName).exists())
265 if (n <= quint32(USHRT_MAX))
267 if (fancy)
269 fileName = basePath.absoluteFilePath(QString("%1 (%2).%3").arg(baseName, QString::number(n++), extension));
271 else
273 fileName = basePath.absoluteFilePath(QString("%1.%2.%3").arg(baseName, QString::number(n++, 16).rightJustified(4, QLatin1Char('0')), extension));
276 else
278 qWarning("Failed to generate unique file name!");
279 return QString();
283 if (placeholder && (!fileName.isEmpty()))
285 QFile placeholder(fileName);
286 if (placeholder.open(QIODevice::WriteOnly))
288 placeholder.close();
292 return fileName;
295 ///////////////////////////////////////////////////////////////////////////////
296 // COMPUTE PARITY
297 ///////////////////////////////////////////////////////////////////////////////
300 * Compute parity in parallel
301 * http://www.graphics.stanford.edu/~seander/bithacks.html#ParityParallel
303 bool MUtils::parity(quint32 value)
305 value ^= value >> 16;
306 value ^= value >> 8;
307 value ^= value >> 4;
308 value &= 0xf;
309 return ((0x6996 >> value) & 1) != 0;
312 ///////////////////////////////////////////////////////////////////////////////
313 // TEMP FOLDER
314 ///////////////////////////////////////////////////////////////////////////////
316 static QScopedPointer<MUtils::Internal::DirLock> g_temp_folder_file;
317 static QReadWriteLock g_temp_folder_lock;
319 static QString try_create_subfolder(const QString &baseDir, const QString &postfix)
321 const QString baseDirPath = QDir(baseDir).absolutePath();
322 for(int i = 0; i < 32; i++)
324 QDir directory(baseDirPath);
325 if(directory.mkpath(postfix) && directory.cd(postfix))
327 return directory.canonicalPath();
330 return QString();
333 static MUtils::Internal::DirLock *try_init_temp_folder(const QString &baseDir)
335 const QString tempPath = try_create_subfolder(baseDir, MUtils::next_rand_str());
336 if(!tempPath.isEmpty())
338 for(int i = 0; i < 32; i++)
340 MUtils::Internal::DirLock *lockFile = NULL;
343 lockFile = new MUtils::Internal::DirLock(tempPath);
344 return lockFile;
346 catch(MUtils::Internal::DirLockException&)
348 /*ignore error and try again*/
352 return NULL;
355 static bool temp_folder_cleanup_helper(const QString &tempPath)
357 size_t delay = 1;
358 static const size_t MAX_DELAY = 8192;
359 forever
361 QDir::setCurrent(QDir::rootPath());
362 if(MUtils::remove_directory(tempPath, true))
364 return true;
366 else
368 if(delay > MAX_DELAY)
370 return false;
372 MUtils::OS::sleep_ms(delay);
373 delay *= 2;
378 static void temp_folder_cleaup(void)
380 QWriteLocker writeLock(&g_temp_folder_lock);
382 //Clean the directory
383 while(!g_temp_folder_file.isNull())
385 const QString tempPath = g_temp_folder_file->getPath();
386 g_temp_folder_file.reset(NULL);
387 if(!temp_folder_cleanup_helper(tempPath))
389 MUtils::OS::system_message_wrn(L"Temp Cleaner", L"Warning: Not all temporary files could be removed!");
394 const QString &MUtils::temp_folder(void)
396 QReadLocker readLock(&g_temp_folder_lock);
398 //Already initialized?
399 if(!g_temp_folder_file.isNull())
401 return g_temp_folder_file->getPath();
404 //Obtain the write lock to initilaize
405 readLock.unlock();
406 QWriteLocker writeLock(&g_temp_folder_lock);
408 //Still uninitilaized?
409 if(!g_temp_folder_file.isNull())
411 return g_temp_folder_file->getPath();
414 //Try the %TMP% or %TEMP% directory first
415 if(MUtils::Internal::DirLock *lockFile = try_init_temp_folder(QDir::tempPath()))
417 g_temp_folder_file.reset(lockFile);
418 atexit(temp_folder_cleaup);
419 return lockFile->getPath();
422 qWarning("%%TEMP%% directory not found -> trying fallback mode now!");
423 static const OS::known_folder_t FOLDER_ID[2] = { OS::FOLDER_LOCALAPPDATA, OS::FOLDER_SYSTROOT_DIR };
424 for(size_t id = 0; id < 2; id++)
426 const QString &knownFolder = OS::known_folder(FOLDER_ID[id]);
427 if(!knownFolder.isEmpty())
429 const QString tempRoot = try_create_subfolder(knownFolder, QLatin1String("TEMP"));
430 if(!tempRoot.isEmpty())
432 if(MUtils::Internal::DirLock *lockFile = try_init_temp_folder(tempRoot))
434 g_temp_folder_file.reset(lockFile);
435 atexit(temp_folder_cleaup);
436 return lockFile->getPath();
442 qFatal("Temporary directory could not be initialized !!!");
443 return (*((QString*)NULL));
446 ///////////////////////////////////////////////////////////////////////////////
447 // REMOVE DIRECTORY / FILE
448 ///////////////////////////////////////////////////////////////////////////////
450 static const QFile::Permissions FILE_PERMISSIONS_NONE = QFile::ReadOther | QFile::WriteOther;
452 bool MUtils::remove_file(const QString &fileName)
454 QFileInfo fileInfo(fileName);
456 for(size_t round = 0; round < 13; ++round)
458 if (round > 0)
460 MUtils::OS::sleep_ms(round);
461 fileInfo.refresh();
463 if (fileInfo.exists())
465 QFile file(fileName);
466 if (round > 0)
468 file.setPermissions(FILE_PERMISSIONS_NONE);
470 file.remove();
471 fileInfo.refresh();
473 if (!fileInfo.exists())
475 return true; /*success*/
479 qWarning("Could not delete \"%s\"", MUTILS_UTF8(fileName));
480 return false;
483 bool MUtils::remove_directory(const QString &folderPath, const bool &recursive)
485 const QDir folder(folderPath);
487 if(recursive && folder.exists())
489 const QFileInfoList entryList = folder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
490 for(QFileInfoList::ConstIterator iter = entryList.constBegin(); iter != entryList.constEnd(); iter++)
492 if(iter->isDir())
494 remove_directory(iter->canonicalFilePath(), true);
496 else
498 remove_file(iter->canonicalFilePath());
503 for(size_t round = 0; round < 13; ++round)
505 if(round > 0)
507 MUtils::OS::sleep_ms(round);
508 folder.refresh();
510 if (folder.exists())
512 QDir parent = folder;
513 if (parent.cdUp())
515 if (round > 0)
517 QFile::setPermissions(folder.absolutePath(), FILE_PERMISSIONS_NONE);
519 parent.rmdir(folder.dirName());
520 folder.refresh();
523 if (!folder.exists())
525 return true; /*success*/
529 qWarning("Could not rmdir \"%s\"", MUTILS_UTF8(folderPath));
530 return false;
533 ///////////////////////////////////////////////////////////////////////////////
534 // PROCESS UTILS
535 ///////////////////////////////////////////////////////////////////////////////
537 static void prependToPath(QProcessEnvironment &env, const QString &value)
539 static const QLatin1String PATH("PATH");
540 const QString path = env.value(PATH, QString()).trimmed();
541 env.insert(PATH, path.isEmpty() ? value : QString("%1;%2").arg(value, path));
544 void MUtils::init_process(QProcess &process, const QString &wokringDir, const bool bReplaceTempDir, const QStringList *const extraPaths, const QHash<QString, QString> *const extraEnv)
546 //Environment variable names
547 static const char *const ENVVAR_NAMES_TMP[] =
549 "TEMP", "TMP", "TMPDIR", "HOME", "USERPROFILE", "HOMEPATH", NULL
551 static const char *const ENVVAR_NAMES_SYS[] =
553 "WINDIR", "SYSTEMROOT", NULL
555 static const char *const ENVVAR_NAMES_DEL[] =
557 "HTTP_PROXY", "FTP_PROXY", "NO_PROXY", "HOME", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
558 "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LANG", NULL
561 //Initialize environment
562 QProcessEnvironment env = process.processEnvironment();
563 if (env.isEmpty())
565 env = QProcessEnvironment::systemEnvironment();
568 //Clean enviroment variables that might affect our tools
569 for(const char *const *ptr = ENVVAR_NAMES_DEL; *ptr; ++ptr)
571 env.remove(QString::fromLatin1(*ptr));
574 //Set up system root directory
575 const QString sysRoot = QDir::toNativeSeparators(OS::known_folder(OS::FOLDER_SYSTROOT_DIR));
576 if (!sysRoot.isEmpty())
578 for (const char *const *ptr = ENVVAR_NAMES_SYS; *ptr; ++ptr)
580 env.insert(QString::fromLatin1(*ptr), sysRoot);
584 //Replace TEMP directory in environment
585 const QString tempDir = QDir::toNativeSeparators(temp_folder());
586 if(bReplaceTempDir)
588 for (const char *const *ptr = ENVVAR_NAMES_TMP; *ptr; ++ptr)
590 env.insert(QString::fromLatin1(*ptr), tempDir);
594 //Setup PATH variable
595 prependToPath(env, tempDir);
596 if (extraPaths && (!extraPaths->isEmpty()))
598 QListIterator<QString> iter(*extraPaths);
599 iter.toBack();
600 while (iter.hasPrevious())
602 prependToPath(env, QDir::toNativeSeparators(iter.previous()));
606 //Setup environment
607 if (extraEnv && (!extraEnv->isEmpty()))
609 for (QHash<QString, QString>::ConstIterator iter = extraEnv->constBegin(); iter != extraEnv->constEnd(); iter++)
611 env.insert(iter.key(), iter.value());
615 //Setup QPorcess object
616 process.setWorkingDirectory(wokringDir);
617 process.setProcessChannelMode(QProcess::MergedChannels);
618 process.setReadChannel(QProcess::StandardOutput);
619 process.setProcessEnvironment(env);
622 ///////////////////////////////////////////////////////////////////////////////
623 // NATURAL ORDER STRING COMPARISON
624 ///////////////////////////////////////////////////////////////////////////////
626 static bool natural_string_sort_helper(const QString &str1, const QString &str2)
628 return (MUtils::Internal::NaturalSort::strnatcmp(MUTILS_WCHR(str1), MUTILS_WCHR(str2)) < 0);
631 static bool natural_string_sort_helper_fold_case(const QString &str1, const QString &str2)
633 return (MUtils::Internal::NaturalSort::strnatcasecmp(MUTILS_WCHR(str1), MUTILS_WCHR(str2)) < 0);
636 void MUtils::natural_string_sort(QStringList &list, const bool bIgnoreCase)
638 qSort(list.begin(), list.end(), bIgnoreCase ? natural_string_sort_helper_fold_case : natural_string_sort_helper);
641 ///////////////////////////////////////////////////////////////////////////////
642 // CLEAN FILE PATH
643 ///////////////////////////////////////////////////////////////////////////////
645 static QMutex g_clean_file_name_mutex;
646 static QScopedPointer<const QList<QPair<QRegExp,QString>>> g_clean_file_name_regex;
648 static void clean_file_name_make_pretty(QString &str)
650 static const struct { const char *p; const char *r; } PATTERN[] =
652 { "^\\s*\"([^\"]*)\"\\s*$", "\\1" }, //Remove straight double quotes around the whole string
653 { "\"([^\"]*)\"", "\xE2\x80\x9C\\1\xE2\x80\x9D" }, //Replace remaining pairs of straight double quotes with opening/closing double quote
654 { "^[\\\\/:]+([^\\\\/:]+.*)$", "\\1" }, //Remove leading slash, backslash and colon characters
655 { "^(.*[^\\\\/:]+)[\\\\/:]+$", "\\1" }, //Remove trailing slash, backslash and colon characters
656 { "(\\s*[\\\\/:]\\s*)+", " - " }, //Replace any slash, backslash or colon character that appears in the middle
657 { NULL, NULL }
660 QMutexLocker locker(&g_clean_file_name_mutex);
662 if (g_clean_file_name_regex.isNull())
664 QScopedPointer<QList<QPair<QRegExp, QString>>> list(new QList<QPair<QRegExp, QString>>());
665 for (size_t i = 0; PATTERN[i].p; ++i)
667 list->append(qMakePair(QRegExp(QString::fromUtf8(PATTERN[i].p), Qt::CaseInsensitive), PATTERN[i].r ? QString::fromUtf8(PATTERN[i].r) : QString()));
669 g_clean_file_name_regex.reset(list.take());
672 bool keepOnGoing = !str.isEmpty();
673 while(keepOnGoing)
675 const QString prev = str;
676 keepOnGoing = false;
677 for (QList<QPair<QRegExp, QString>>::ConstIterator iter = g_clean_file_name_regex->constBegin(); iter != g_clean_file_name_regex->constEnd(); ++iter)
679 str.replace(iter->first, iter->second);
680 if (str.compare(prev))
682 str = str.simplified();
683 keepOnGoing = !str.isEmpty();
684 break;
690 QString MUtils::clean_file_name(const QString &name, const bool &pretty)
692 static const QLatin1Char REPLACEMENT_CHAR('_');
693 static const char FILENAME_ILLEGAL_CHARS[] = "<>:\"/\\|?*";
694 static const char *const FILENAME_RESERVED_NAMES[] =
696 "CON", "PRN", "AUX", "NUL",
697 "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
698 "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", NULL
701 QString result(name);
702 if (pretty)
704 clean_file_name_make_pretty(result);
707 for(QString::Iterator iter = result.begin(); iter != result.end(); iter++)
709 if (iter->category() == QChar::Other_Control)
711 *iter = REPLACEMENT_CHAR;
715 for(size_t i = 0; FILENAME_ILLEGAL_CHARS[i]; i++)
717 result.replace(QLatin1Char(FILENAME_ILLEGAL_CHARS[i]), REPLACEMENT_CHAR);
720 trim_right(result);
721 while (result.endsWith(QLatin1Char('.')))
723 result.chop(1);
724 trim_right(result);
727 for (size_t i = 0; FILENAME_RESERVED_NAMES[i]; i++)
729 const QString reserved = QString::fromLatin1(FILENAME_RESERVED_NAMES[i]);
730 if ((!result.compare(reserved, Qt::CaseInsensitive)) || result.startsWith(reserved + QLatin1Char('.'), Qt::CaseInsensitive))
732 result.replace(0, reserved.length(), QString().leftJustified(reserved.length(), REPLACEMENT_CHAR));
736 return result;
739 static QPair<QString,QString> clean_file_path_get_prefix(const QString path)
741 static const char *const PREFIXES[] =
743 "//?/", "//", "/", NULL
745 const QString posixPath = QDir::fromNativeSeparators(path.trimmed());
746 for (int i = 0; PREFIXES[i]; i++)
748 const QString prefix = QString::fromLatin1(PREFIXES[i]);
749 if (posixPath.startsWith(prefix))
751 return qMakePair(prefix, posixPath.mid(prefix.length()));
754 return qMakePair(QString(), posixPath);
757 QString MUtils::clean_file_path(const QString &path, const bool &pretty)
759 const QPair<QString, QString> prefix = clean_file_path_get_prefix(path);
761 QStringList parts = prefix.second.split(QLatin1Char('/'), QString::SkipEmptyParts);
762 for(int i = 0; i < parts.count(); i++)
764 if((i == 0) && (parts[i].length() == 2) && parts[i][0].isLetter() && (parts[i][1] == QLatin1Char(':')))
766 continue; //handle case "c:\"
768 parts[i] = MUtils::clean_file_name(parts[i], pretty);
771 const QString cleanPath = parts.join(QLatin1String("/"));
772 return prefix.first.isEmpty() ? cleanPath : prefix.first + cleanPath;
775 ///////////////////////////////////////////////////////////////////////////////
776 // REGULAR EXPESSION HELPER
777 ///////////////////////////////////////////////////////////////////////////////
779 bool MUtils::regexp_parse_uint32(const QRegExp &regexp, quint32 &value)
781 return regexp_parse_uint32(regexp, &value, 1U, 1U);
784 bool MUtils::regexp_parse_int32(const QRegExp &regexp, qint32 &value)
786 return regexp_parse_int32(regexp, &value, 1U, 1U);
789 bool MUtils::regexp_parse_uint32(const QRegExp &regexp, quint32 &value, const size_t &offset)
791 return regexp_parse_uint32(regexp, &value, offset, 1U);
794 bool MUtils::regexp_parse_int32(const QRegExp &regexp, qint32 &value, const size_t &offset)
796 return regexp_parse_int32(regexp, &value, offset, 1U);
799 bool MUtils::regexp_parse_uint32(const QRegExp &regexp, quint32 *values, const size_t &count)
801 return regexp_parse_uint32(regexp, values, 1U, count);
804 bool MUtils::regexp_parse_int32(const QRegExp &regexp, qint32 *values, const size_t &count)
806 return regexp_parse_int32(regexp, values, 1U, count);
809 bool MUtils::regexp_parse_uint32(const QRegExp &regexp, quint32 *values, const size_t &offset, const size_t &count)
811 const QStringList caps = regexp.capturedTexts();
813 if (caps.isEmpty() || (quint32(caps.count()) <= count))
815 return false;
818 for (size_t i = 0; i < count; i++)
820 bool ok = false;
821 values[i] = caps[offset+i].toUInt(&ok);
822 if (!ok)
824 return false;
828 return true;
831 bool MUtils::regexp_parse_int32(const QRegExp &regexp, qint32 *values, const size_t &offset, const size_t &count)
833 const QStringList caps = regexp.capturedTexts();
835 if (caps.isEmpty() || (quint32(caps.count()) <= count))
837 return false;
840 for (size_t i = 0; i < count; i++)
842 bool ok = false;
843 values[i] = caps[offset+i].toInt(&ok);
844 if (!ok)
846 return false;
850 return true;
853 ///////////////////////////////////////////////////////////////////////////////
854 // AVAILABLE CODEPAGES
855 ///////////////////////////////////////////////////////////////////////////////
857 QStringList MUtils::available_codepages(const bool &noAliases)
859 QStringList codecList;
860 QList<QByteArray> availableCodecs = QTextCodec::availableCodecs();
862 while(!availableCodecs.isEmpty())
864 const QByteArray current = availableCodecs.takeFirst();
865 if(!current.toLower().startsWith("system"))
867 codecList << QString::fromLatin1(current.constData(), current.size());
868 if(noAliases)
870 if(QTextCodec *const currentCodec = QTextCodec::codecForName(current.constData()))
872 const QList<QByteArray> aliases = currentCodec->aliases();
873 for(QList<QByteArray>::ConstIterator iter = aliases.constBegin(); iter != aliases.constEnd(); iter++)
875 availableCodecs.removeAll(*iter);
882 return codecList;
885 ///////////////////////////////////////////////////////////////////////////////
886 // FP MATH SUPPORT
887 ///////////////////////////////////////////////////////////////////////////////
889 MUtils::fp_parts_t MUtils::break_fp(const double value)
891 fp_parts_t result = { };
892 if (_finite(value))
894 result.parts[1] = modf(value, &result.parts[0]);
896 else
898 result.parts[0] = std::numeric_limits<double>::quiet_NaN();
899 result.parts[1] = std::numeric_limits<double>::quiet_NaN();
901 return result;
904 ///////////////////////////////////////////////////////////////////////////////
905 // INITIALIZER
906 ///////////////////////////////////////////////////////////////////////////////
908 int MUtils::Internal::MUTILS_INITIALIZER(const char *const buildKey, const bool debug)
910 static const bool INTERNAL_DEBUG_FLAG = MUTILS_DEBUG;
911 static const char *const INTERNAL_BUILD_KEY = MUTILS_BUILD_KEY;
913 if((debug != INTERNAL_DEBUG_FLAG) || strncmp(buildKey, INTERNAL_BUILD_KEY, 11))
915 MUtils::OS::system_message_err(L"MUtils", L"FATAL ERROR: MUtils library initialization has failed");
916 abort();
919 volatile int _result = MUTILS_INTERFACE;
920 return _result;