X-Git-Url: http://git.osdn.net/view?p=mutilities%2FMUtilities.git;a=blobdiff_plain;f=src%2FGlobal.cpp;h=447c758a748071d309a34002ec7fd1a98e6d5b29;hp=21a7454072140999d821f75a266263dbb7fffba4;hb=0ee110053bfce34ab64a462b51eae38b0a8a7457;hpb=78fa3cf1465df987d56573a67167779a3e515a86 diff --git a/src/Global.cpp b/src/Global.cpp index 21a7454..447c758 100644 --- a/src/Global.cpp +++ b/src/Global.cpp @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// // MuldeR's Utilities for Qt -// Copyright (C) 2004-2015 LoRd_MuldeR +// Copyright (C) 2004-2019 LoRd_MuldeR // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,8 @@ //MUtils #include #include +#include +#include "Internal.h" //Internal #include "DirLocker.h" @@ -36,6 +38,11 @@ #include #include #include +#include +#include +#include +#include +#include //CRT #include @@ -47,66 +54,242 @@ #include #endif +//Global +const QString MUtils::Internal::g_empty; + /////////////////////////////////////////////////////////////////////////////// // Random Support /////////////////////////////////////////////////////////////////////////////// +#ifndef _CRT_RAND_S +#define rand_s(X) (true) +#endif + +//Per-thread init flag +static QThreadStorage g_srand_flag; + +//32-Bit wrapper for qrand() +#define QRAND() ((static_cast(qrand()) & 0xFFFF) | (static_cast(qrand()) << 16U)) + //Robert Jenkins' 96 bit Mix Function -static unsigned int mix_function(const unsigned int x, const unsigned int y, const unsigned int z) +static quint32 mix_function(quint32 a, quint32 b, quint32 c) { - unsigned int a = x; - unsigned int b = y; - unsigned int c = z; - a=a-b; a=a-c; a=a^(c >> 13); - b=b-c; b=b-a; b=b^(a << 8 ); + b=b-c; b=b-a; b=b^(a << 8); c=c-a; c=c-b; c=c^(b >> 13); a=a-b; a=a-c; a=a^(c >> 12); b=b-c; b=b-a; b=b^(a << 16); - c=c-a; c=c-b; c=c^(b >> 5 ); - a=a-b; a=a-c; a=a^(c >> 3 ); + c=c-a; c=c-b; c=c^(b >> 5); + a=a-b; a=a-c; a=a^(c >> 3); b=b-c; b=b-a; b=b^(a << 10); c=c-a; c=c-b; c=c^(b >> 15); return a ^ b ^ c; } -void MUtils::seed_rand(void) +static void seed_rand(void) { - qsrand(mix_function(clock(), time(NULL), _getpid())); + QDateTime build(MUtils::Version::lib_build_date(), MUtils::Version::lib_build_time()); + const quint32 seed_0 = mix_function(MUtils::OS::process_id(), MUtils::OS::thread_id(), build.toMSecsSinceEpoch()); + qsrand(mix_function(clock(), time(NULL), seed_0)); } -quint32 MUtils::next_rand32(void) +static quint32 rand_fallback(void) { - quint32 rnd = 0xDEADBEEF; + Q_ASSERT(RAND_MAX >= 0x7FFF); -#ifdef _CRT_RAND_S - if(rand_s(&rnd) == 0) + if (!(g_srand_flag.hasLocalData() && g_srand_flag.localData())) { - return rnd; + seed_rand(); + g_srand_flag.setLocalData(true); } -#endif //_CRT_RAND_S - for(size_t i = 0; i < sizeof(quint32); i++) + quint32 rnd_val = mix_function(0x32288EA3, clock(), time(NULL)); + + for (size_t i = 0; i < 42; i++) { - rnd = (rnd << 8) ^ qrand(); + rnd_val = mix_function(rnd_val, QRAND(), QRAND()); + rnd_val = mix_function(QRAND(), rnd_val, QRAND()); + rnd_val = mix_function(QRAND(), QRAND(), rnd_val); } + return rnd_val; +} + +quint32 MUtils::next_rand_u32(void) +{ + quint32 rnd; + if (rand_s(&rnd)) + { + return rand_fallback(); + } return rnd; } -quint64 MUtils::next_rand64(void) +quint32 MUtils::next_rand_u32(const quint32 max) +{ + static const uint32_t DIV_LUT[64] = + { + 0xFFFFFFFF, 0xFFFFFFFF, 0x80000000, 0x55555556, 0x40000000, 0x33333334, 0x2AAAAAAB, 0x24924925, + 0x20000000, 0x1C71C71D, 0x1999999A, 0x1745D175, 0x15555556, 0x13B13B14, 0x12492493, 0x11111112, + 0x10000000, 0x0F0F0F10, 0x0E38E38F, 0x0D79435F, 0x0CCCCCCD, 0x0C30C30D, 0x0BA2E8BB, 0x0B21642D, + 0x0AAAAAAB, 0x0A3D70A4, 0x09D89D8A, 0x097B425F, 0x0924924A, 0x08D3DCB1, 0x08888889, 0x08421085, + 0x08000000, 0x07C1F07D, 0x07878788, 0x07507508, 0x071C71C8, 0x06EB3E46, 0x06BCA1B0, 0x06906907, + 0x06666667, 0x063E7064, 0x06186187, 0x05F417D1, 0x05D1745E, 0x05B05B06, 0x0590B217, 0x0572620B, + 0x05555556, 0x0539782A, 0x051EB852, 0x05050506, 0x04EC4EC5, 0x04D4873F, 0x04BDA130, 0x04A7904B, + 0x04924925, 0x047DC120, 0x0469EE59, 0x0456C798, 0x04444445, 0x04325C54, 0x04210843, 0x04104105 + }; + return (max < 64) ? (next_rand_u32() / DIV_LUT[max]) : (next_rand_u32() / (UINT32_MAX / max + 1U)); +} + + +quint64 MUtils::next_rand_u64(void) +{ + return (quint64(next_rand_u32()) << 32) | quint64(next_rand_u32()); +} + +QString MUtils::next_rand_str(const bool &bLong) +{ + if (bLong) + { + return next_rand_str(false) + next_rand_str(false); + } + else + { + return QString::number(next_rand_u64(), 16).rightJustified(16, QLatin1Char('0')); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// STRING UTILITY FUNCTIONS +/////////////////////////////////////////////////////////////////////////////// + +static QScopedPointer g_str_trim_rx_r; +static QScopedPointer g_str_trim_rx_l; +static QMutex g_str_trim_lock; + +static QString& trim_helper(QString &str, QScopedPointer ®ex, const char *const pattern) +{ + QMutexLocker lock(&g_str_trim_lock); + if (regex.isNull()) + { + regex.reset(new QRegExp(QLatin1String(pattern))); + } + str.remove(*regex.data()); + return str; +} + +QString& MUtils::trim_right(QString &str) +{ + static const char *const TRIM_RIGHT = "\\s+$"; + return trim_helper(str, g_str_trim_rx_r, TRIM_RIGHT); +} + +QString& MUtils::trim_left(QString &str) +{ + static const char *const TRIM_LEFT = "^\\s+"; + return trim_helper(str, g_str_trim_rx_l, TRIM_LEFT); +} + +QString MUtils::trim_right(const QString &str) +{ + QString temp(str); + return trim_right(temp); +} + +QString MUtils::trim_left(const QString &str) +{ + QString temp(str); + return trim_left(temp); +} + +/////////////////////////////////////////////////////////////////////////////// +// GENERATE FILE NAME +/////////////////////////////////////////////////////////////////////////////// + +QString MUtils::make_temp_file(const QString &basePath, const QString &extension, const bool placeholder) +{ + return make_temp_file(QDir(basePath), extension, placeholder); +} + +QString MUtils::make_temp_file(const QDir &basePath, const QString &extension, const bool placeholder) +{ + if (extension.isEmpty()) + { + qWarning("Cannot generate temp file name with invalid parameters!"); + return QString(); + } + + for(int i = 0; i < 4096; i++) + { + const QString tempFileName = basePath.absoluteFilePath(QString("%1.%2").arg(next_rand_str(), extension)); + if(!QFileInfo(tempFileName).exists()) + { + if(placeholder) + { + QFile file(tempFileName); + if(file.open(QFile::ReadWrite)) + { + file.close(); + return tempFileName; + } + } + else + { + return tempFileName; + } + } + } + + qWarning("Failed to generate temp file name!"); + return QString(); +} + +QString MUtils::make_unique_file(const QString &basePath, const QString &baseName, const QString &extension, const bool fancy, const bool placeholder) { - return (quint64(next_rand32()) << 32) | quint64(next_rand32()); + return make_unique_file(QDir(basePath), baseName, extension, fancy); } -QString MUtils::rand_str(const bool &bLong) +QString MUtils::make_unique_file(const QDir &basePath, const QString &baseName, const QString &extension, const bool fancy, const bool placeholder) { - if(!bLong) + if (baseName.isEmpty() || extension.isEmpty()) + { + qWarning("Cannot generate unique file name with invalid parameters!"); + return QString(); + } + + quint32 n = fancy ? 2 : 0; + QString fileName = fancy ? basePath.absoluteFilePath(QString("%1.%2").arg(baseName, extension)) : QString(); + while (fileName.isEmpty() || QFileInfo(fileName).exists()) { - return QString::number(next_rand64(), 16).rightJustified(16, QLatin1Char('0')); + if (n <= quint32(USHRT_MAX)) + { + if (fancy) + { + fileName = basePath.absoluteFilePath(QString("%1 (%2).%3").arg(baseName, QString::number(n++), extension)); + } + else + { + fileName = basePath.absoluteFilePath(QString("%1.%2.%3").arg(baseName, QString::number(n++, 16).rightJustified(4, QLatin1Char('0')), extension)); + } + } + else + { + qWarning("Failed to generate unique file name!"); + return QString(); + } } - return QString("%1%2").arg(rand_str(false), rand_str(false)); + + if (placeholder && (!fileName.isEmpty())) + { + QFile placeholder(fileName); + if (placeholder.open(QIODevice::WriteOnly)) + { + placeholder.close(); + } + } + + return fileName; } /////////////////////////////////////////////////////////////////////////////// @@ -149,7 +332,7 @@ static QString try_create_subfolder(const QString &baseDir, const QString &postf static MUtils::Internal::DirLock *try_init_temp_folder(const QString &baseDir) { - const QString tempPath = try_create_subfolder(baseDir, MUtils::rand_str()); + const QString tempPath = try_create_subfolder(baseDir, MUtils::next_rand_str()); if(!tempPath.isEmpty()) { for(int i = 0; i < 32; i++) @@ -195,7 +378,7 @@ static bool temp_folder_cleanup_helper(const QString &tempPath) static void temp_folder_cleaup(void) { QWriteLocker writeLock(&g_temp_folder_lock); - + //Clean the directory while(!g_temp_folder_file.isNull()) { @@ -269,57 +452,39 @@ static const QFile::Permissions FILE_PERMISSIONS_NONE = QFile::ReadOther | QFile bool MUtils::remove_file(const QString &fileName) { QFileInfo fileInfo(fileName); - if(!(fileInfo.exists() && fileInfo.isFile())) - { - return true; - } - for(int i = 0; i < 32; i++) + for(size_t round = 0; round < 13; ++round) { - QFile file(fileName); - file.setPermissions(FILE_PERMISSIONS_NONE); - if((!(fileInfo.exists() && fileInfo.isFile())) || file.remove()) + if (round > 0) { - return true; + MUtils::OS::sleep_ms(round); + fileInfo.refresh(); } - fileInfo.refresh(); - } - - qWarning("Could not delete \"%s\"", MUTILS_UTF8(fileName)); - return false; -} - -static bool remove_directory_helper(const QDir &folder) -{ - if(!folder.exists()) - { - return true; - } - const QString dirName = folder.dirName(); - if(!dirName.isEmpty()) - { - QDir parent(folder); - if(parent.cdUp()) + if (fileInfo.exists()) { - QFile::setPermissions(folder.absolutePath(), FILE_PERMISSIONS_NONE); - if(parent.rmdir(dirName)) + QFile file(fileName); + if (round > 0) { - return true; + file.setPermissions(FILE_PERMISSIONS_NONE); } + file.remove(); + fileInfo.refresh(); + } + if (!fileInfo.exists()) + { + return true; /*success*/ } } + + qWarning("Could not delete \"%s\"", MUTILS_UTF8(fileName)); return false; } bool MUtils::remove_directory(const QString &folderPath, const bool &recursive) { - QDir folder(folderPath); - if(!folder.exists()) - { - return true; - } + const QDir folder(folderPath); - if(recursive) + if(recursive && folder.exists()) { const QFileInfoList entryList = folder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden); for(QFileInfoList::ConstIterator iter = entryList.constBegin(); iter != entryList.constEnd(); iter++) @@ -328,20 +493,37 @@ bool MUtils::remove_directory(const QString &folderPath, const bool &recursive) { remove_directory(iter->canonicalFilePath(), true); } - else if(iter->isFile()) + else { remove_file(iter->canonicalFilePath()); } } } - for(int i = 0; i < 32; i++) + for(size_t round = 0; round < 13; ++round) { - if(remove_directory_helper(folder)) + if(round > 0) { - return true; + MUtils::OS::sleep_ms(round); + folder.refresh(); + } + if (folder.exists()) + { + QDir parent = folder; + if (parent.cdUp()) + { + if (round > 0) + { + QFile::setPermissions(folder.absolutePath(), FILE_PERMISSIONS_NONE); + } + parent.rmdir(folder.dirName()); + folder.refresh(); + } + } + if (!folder.exists()) + { + return true; /*success*/ } - folder.refresh(); } qWarning("Could not rmdir \"%s\"", MUTILS_UTF8(folderPath)); @@ -352,44 +534,84 @@ bool MUtils::remove_directory(const QString &folderPath, const bool &recursive) // PROCESS UTILS /////////////////////////////////////////////////////////////////////////////// -void MUtils::init_process(QProcess &process, const QString &wokringDir, const bool bReplaceTempDir) +static void prependToPath(QProcessEnvironment &env, const QString &value) +{ + static const QLatin1String PATH("PATH"); + const QString path = env.value(PATH, QString()).trimmed(); + env.insert(PATH, path.isEmpty() ? value : QString("%1;%2").arg(value, path)); +} + +void MUtils::init_process(QProcess &process, const QString &wokringDir, const bool bReplaceTempDir, const QStringList *const extraPaths, const QHash *const extraEnv) { //Environment variable names - static const char *const s_envvar_names_temp[] = + static const char *const ENVVAR_NAMES_TMP[] = { "TEMP", "TMP", "TMPDIR", "HOME", "USERPROFILE", "HOMEPATH", NULL }; - static const char *const s_envvar_names_remove[] = + static const char *const ENVVAR_NAMES_SYS[] = { - "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 + "WINDIR", "SYSTEMROOT", NULL + }; + static const char *const ENVVAR_NAMES_DEL[] = + { + "HTTP_PROXY", "FTP_PROXY", "NO_PROXY", "HOME", "LC_ALL", "LC_COLLATE", "LC_CTYPE", + "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LANG", NULL }; //Initialize environment QProcessEnvironment env = process.processEnvironment(); - if(env.isEmpty()) env = QProcessEnvironment::systemEnvironment(); + if (env.isEmpty()) + { + env = QProcessEnvironment::systemEnvironment(); + } - //Clean a number of enviroment variables that might affect our tools - for(size_t i = 0; s_envvar_names_remove[i]; i++) + //Clean enviroment variables that might affect our tools + for(const char *const *ptr = ENVVAR_NAMES_DEL; *ptr; ++ptr) { - env.remove(QString::fromLatin1(s_envvar_names_remove[i])); - env.remove(QString::fromLatin1(s_envvar_names_remove[i]).toLower()); + env.remove(QString::fromLatin1(*ptr)); } - const QString tempDir = QDir::toNativeSeparators(temp_folder()); + //Set up system root directory + const QString sysRoot = QDir::toNativeSeparators(OS::known_folder(OS::FOLDER_SYSTROOT_DIR)); + if (!sysRoot.isEmpty()) + { + for (const char *const *ptr = ENVVAR_NAMES_SYS; *ptr; ++ptr) + { + env.insert(QString::fromLatin1(*ptr), sysRoot); + } + } //Replace TEMP directory in environment + const QString tempDir = QDir::toNativeSeparators(temp_folder()); if(bReplaceTempDir) { - for(size_t i = 0; s_envvar_names_temp[i]; i++) + for (const char *const *ptr = ENVVAR_NAMES_TMP; *ptr; ++ptr) { - env.insert(s_envvar_names_temp[i], tempDir); + env.insert(QString::fromLatin1(*ptr), tempDir); } } //Setup PATH variable - const QString path = env.value("PATH", QString()).trimmed(); - env.insert("PATH", path.isEmpty() ? tempDir : QString("%1;%2").arg(tempDir, path)); + prependToPath(env, tempDir); + if (extraPaths && (!extraPaths->isEmpty())) + { + QListIterator iter(*extraPaths); + iter.toBack(); + while (iter.hasPrevious()) + { + prependToPath(env, QDir::toNativeSeparators(iter.previous())); + } + } + //Setup environment + if (extraEnv && (!extraEnv->isEmpty())) + { + for (QHash::ConstIterator iter = extraEnv->constBegin(); iter != extraEnv->constEnd(); iter++) + { + env.insert(iter.key(), iter.value()); + } + } + //Setup QPorcess object process.setWorkingDirectory(wokringDir); process.setProcessChannelMode(QProcess::MergedChannels); @@ -420,52 +642,134 @@ void MUtils::natural_string_sort(QStringList &list, const bool bIgnoreCase) // CLEAN FILE PATH /////////////////////////////////////////////////////////////////////////////// -static const struct +static QMutex g_clean_file_name_mutex; +static QScopedPointer>> g_clean_file_name_regex; + +static void clean_file_name_make_pretty(QString &str) { - const char *const search; - const char *const replace; + static const struct { const char *p; const char *r; } PATTERN[] = + { + { "^\\s*\"([^\"]*)\"\\s*$", "\\1" }, //Remove straight double quotes around the whole string + { "\"([^\"]*)\"", "\xE2\x80\x9C\\1\xE2\x80\x9D" }, //Replace remaining pairs of straight double quotes with opening/closing double quote + { "^[\\\\/:]+([^\\\\/:]+.*)$", "\\1" }, //Remove leading slash, backslash and colon characters + { "^(.*[^\\\\/:]+)[\\\\/:]+$", "\\1" }, //Remove trailing slash, backslash and colon characters + { "(\\s*[\\\\/:]\\s*)+", " - " }, //Replace any slash, backslash or colon character that appears in the middle + { NULL, NULL } + }; + + QMutexLocker locker(&g_clean_file_name_mutex); + + if (g_clean_file_name_regex.isNull()) + { + QScopedPointer>> list(new QList>()); + for (size_t i = 0; PATTERN[i].p; ++i) + { + list->append(qMakePair(QRegExp(QString::fromUtf8(PATTERN[i].p), Qt::CaseInsensitive), PATTERN[i].r ? QString::fromUtf8(PATTERN[i].r) : QString())); + } + g_clean_file_name_regex.reset(list.take()); + } + + bool keepOnGoing = !str.isEmpty(); + while(keepOnGoing) + { + const QString prev = str; + keepOnGoing = false; + for (QList>::ConstIterator iter = g_clean_file_name_regex->constBegin(); iter != g_clean_file_name_regex->constEnd(); ++iter) + { + str.replace(iter->first, iter->second); + if (str.compare(prev)) + { + str = str.simplified(); + keepOnGoing = !str.isEmpty(); + break; + } + } + } } -CLEAN_FILE_NAME[] = -{ - { "\\", "-" }, - { " / ", ", " }, - { "/", "," }, - { ":", "-" }, - { "*", "x" }, - { "?", "!" }, - { "<", "[" }, - { ">", "]" }, - { "|", "!" }, - { "\"", "'" }, - { NULL, NULL } -}; -QString MUtils::clean_file_name(const QString &name) +QString MUtils::clean_file_name(const QString &name, const bool &pretty) { - QString str = name.simplified(); + static const QLatin1Char REPLACEMENT_CHAR('_'); + static const char FILENAME_ILLEGAL_CHARS[] = "<>:\"/\\|?*"; + static const char *const FILENAME_RESERVED_NAMES[] = + { + "CON", "PRN", "AUX", "NUL", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", NULL + }; - for(size_t i = 0; CLEAN_FILE_NAME[i].search; i++) + QString result(name); + if (pretty) { - str.replace(CLEAN_FILE_NAME[i].search, CLEAN_FILE_NAME[i].replace); + clean_file_name_make_pretty(result); + } + + for(QString::Iterator iter = result.begin(); iter != result.end(); iter++) + { + if (iter->category() == QChar::Other_Control) + { + *iter = REPLACEMENT_CHAR; + } + } + + for(size_t i = 0; FILENAME_ILLEGAL_CHARS[i]; i++) + { + result.replace(QLatin1Char(FILENAME_ILLEGAL_CHARS[i]), REPLACEMENT_CHAR); } - QRegExp regExp("\"(.+)\""); - regExp.setMinimal(true); - str.replace(regExp, "`\\1ยด"); - - return str.simplified(); + trim_right(result); + while (result.endsWith(QLatin1Char('.'))) + { + result.chop(1); + trim_right(result); + } + + for (size_t i = 0; FILENAME_RESERVED_NAMES[i]; i++) + { + const QString reserved = QString::fromLatin1(FILENAME_RESERVED_NAMES[i]); + if ((!result.compare(reserved, Qt::CaseInsensitive)) || result.startsWith(reserved + QLatin1Char('.'), Qt::CaseInsensitive)) + { + result.replace(0, reserved.length(), QString().leftJustified(reserved.length(), REPLACEMENT_CHAR)); + } + } + + return result; } -QString MUtils::clean_file_path(const QString &path) +static QPair clean_file_path_get_prefix(const QString path) { - QStringList parts = path.simplified().replace("\\", "/").split("/", QString::SkipEmptyParts); + static const char *const PREFIXES[] = + { + "//?/", "//", "/", NULL + }; + const QString posixPath = QDir::fromNativeSeparators(path.trimmed()); + for (int i = 0; PREFIXES[i]; i++) + { + const QString prefix = QString::fromLatin1(PREFIXES[i]); + if (posixPath.startsWith(prefix)) + { + return qMakePair(prefix, posixPath.mid(prefix.length())); + } + } + return qMakePair(QString(), posixPath); +} + +QString MUtils::clean_file_path(const QString &path, const bool &pretty) +{ + const QPair prefix = clean_file_path_get_prefix(path); + QStringList parts = prefix.second.split(QLatin1Char('/'), QString::SkipEmptyParts); for(int i = 0; i < parts.count(); i++) { - parts[i] = MUtils::clean_file_name(parts[i]); + if((i == 0) && (parts[i].length() == 2) && parts[i][0].isLetter() && (parts[i][1] == QLatin1Char(':'))) + { + continue; //handle case "c:\" + } + parts[i] = MUtils::clean_file_name(parts[i], pretty); } - return parts.join("/"); + const QString cleanPath = parts.join(QLatin1String("/")); + return prefix.first.isEmpty() ? cleanPath : prefix.first + cleanPath; } /////////////////////////////////////////////////////////////////////////////// @@ -474,23 +778,70 @@ QString MUtils::clean_file_path(const QString &path) bool MUtils::regexp_parse_uint32(const QRegExp ®exp, quint32 &value) { - return regexp_parse_uint32(regexp, &value, 1); + return regexp_parse_uint32(regexp, &value, 1U, 1U); +} + +bool MUtils::regexp_parse_int32(const QRegExp ®exp, qint32 &value) +{ + return regexp_parse_int32(regexp, &value, 1U, 1U); +} + +bool MUtils::regexp_parse_uint32(const QRegExp ®exp, quint32 &value, const size_t &offset) +{ + return regexp_parse_uint32(regexp, &value, offset, 1U); +} + +bool MUtils::regexp_parse_int32(const QRegExp ®exp, qint32 &value, const size_t &offset) +{ + return regexp_parse_int32(regexp, &value, offset, 1U); } bool MUtils::regexp_parse_uint32(const QRegExp ®exp, quint32 *values, const size_t &count) { + return regexp_parse_uint32(regexp, values, 1U, count); +} + +bool MUtils::regexp_parse_int32(const QRegExp ®exp, qint32 *values, const size_t &count) +{ + return regexp_parse_int32(regexp, values, 1U, count); +} + +bool MUtils::regexp_parse_uint32(const QRegExp ®exp, quint32 *values, const size_t &offset, const size_t &count) +{ const QStringList caps = regexp.capturedTexts(); - - if(caps.isEmpty() || (quint32(caps.count()) <= count)) + + if (caps.isEmpty() || (quint32(caps.count()) <= count)) { return false; } - for(size_t i = 0; i < count; i++) + for (size_t i = 0; i < count; i++) { bool ok = false; - values[i] = caps[i+1].toUInt(&ok); - if(!ok) + values[i] = caps[offset+i].toUInt(&ok); + if (!ok) + { + return false; + } + } + + return true; +} + +bool MUtils::regexp_parse_int32(const QRegExp ®exp, qint32 *values, const size_t &offset, const size_t &count) +{ + const QStringList caps = regexp.capturedTexts(); + + if (caps.isEmpty() || (quint32(caps.count()) <= count)) + { + return false; + } + + for (size_t i = 0; i < count; i++) + { + bool ok = false; + values[i] = caps[offset+i].toInt(&ok); + if (!ok) { return false; } @@ -532,19 +883,39 @@ QStringList MUtils::available_codepages(const bool &noAliases) } /////////////////////////////////////////////////////////////////////////////// -// SELF-TEST +// FP MATH SUPPORT +/////////////////////////////////////////////////////////////////////////////// + +MUtils::fp_parts_t MUtils::break_fp(const double value) +{ + fp_parts_t result = { }; + if (_finite(value)) + { + result.parts[1] = modf(value, &result.parts[0]); + } + else + { + result.parts[0] = std::numeric_limits::quiet_NaN(); + result.parts[1] = std::numeric_limits::quiet_NaN(); + } + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +// INITIALIZER /////////////////////////////////////////////////////////////////////////////// -int MUtils::Internal::selfTest(const char *const buildKey, const bool debug) +int MUtils::Internal::MUTILS_INITIALIZER(const char *const buildKey, const bool debug) { - static const bool MY_DEBUG_FLAG = MUTILS_DEBUG; - static const char *const MY_BUILD_KEY = __DATE__"@"__TIME__; + static const bool INTERNAL_DEBUG_FLAG = MUTILS_DEBUG; + static const char *const INTERNAL_BUILD_KEY = MUTILS_BUILD_KEY; - if(strncmp(buildKey, MY_BUILD_KEY, 13) || (MY_DEBUG_FLAG != debug)) + if((debug != INTERNAL_DEBUG_FLAG) || strncmp(buildKey, INTERNAL_BUILD_KEY, 11)) { - MUtils::OS::system_message_err(L"MUtils", L"FATAL ERROR: MUtils library version mismatch detected!"); - MUtils::OS::system_message_wrn(L"MUtils", L"Perform a clean(!) re-install of the application to fix the problem!"); + MUtils::OS::system_message_err(L"MUtils", L"FATAL: MUtils library initialization has failed!"); abort(); } - return 0; + + volatile int _result = MUTILS_INTERFACE; + return _result; }