1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2019 LoRd_MuldeR <MuldeR2@GMX.de>
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.
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 //////////////////////////////////////////////////////////////////////////////////
27 #include <MUtils/Global.h>
28 #include <MUtils/OSSupport.h>
29 #include <MUtils/Version.h>
33 #include "DirLocker.h"
34 #include "3rd_party/strnatcmp/include/strnatcmp.h"
38 #include <QReadWriteLock>
43 #include <QListIterator>
45 #include <QThreadStorage>
58 const QString
MUtils::Internal::g_empty
;
60 ///////////////////////////////////////////////////////////////////////////////
62 ///////////////////////////////////////////////////////////////////////////////
65 #define rand_s(X) (true)
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);
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()))
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
);
119 quint32
MUtils::next_rand_u32(void)
124 return rand_fallback();
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
)
155 return next_rand_str(false) + next_rand_str(false);
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
> ®ex
, const char *const pattern
)
173 QMutexLocker
lock(&g_str_trim_lock
);
176 regex
.reset(new QRegExp(QLatin1String(pattern
)));
178 str
.remove(*regex
.data());
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
)
197 return trim_right(temp
);
200 QString
MUtils::trim_left(const QString
&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!");
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())
230 QFile
file(tempFileName
);
231 if(file
.open(QFile::ReadWrite
))
244 qWarning("Failed to generate temp file name!");
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!");
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
))
269 fileName
= basePath
.absoluteFilePath(QString("%1 (%2).%3").arg(baseName
, QString::number(n
++), extension
));
273 fileName
= basePath
.absoluteFilePath(QString("%1.%2.%3").arg(baseName
, QString::number(n
++, 16).rightJustified(4, QLatin1Char('0')), extension
));
278 qWarning("Failed to generate unique file name!");
283 if (placeholder
&& (!fileName
.isEmpty()))
285 QFile
placeholder(fileName
);
286 if (placeholder
.open(QIODevice::WriteOnly
))
295 ///////////////////////////////////////////////////////////////////////////////
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;
309 return ((0x6996 >> value
) & 1) != 0;
312 ///////////////////////////////////////////////////////////////////////////////
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();
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
);
346 catch(MUtils::Internal::DirLockException
&)
348 /*ignore error and try again*/
355 static bool temp_folder_cleanup_helper(const QString
&tempPath
)
358 static const size_t MAX_DELAY
= 8192;
361 QDir::setCurrent(QDir::rootPath());
362 if(MUtils::remove_directory(tempPath
, true))
368 if(delay
> MAX_DELAY
)
372 MUtils::OS::sleep_ms(delay
);
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
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
)
460 MUtils::OS::sleep_ms(round
);
463 if (fileInfo
.exists())
465 QFile
file(fileName
);
468 file
.setPermissions(FILE_PERMISSIONS_NONE
);
473 if (!fileInfo
.exists())
475 return true; /*success*/
479 qWarning("Could not delete \"%s\"", MUTILS_UTF8(fileName
));
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
++)
494 remove_directory(iter
->canonicalFilePath(), true);
498 remove_file(iter
->canonicalFilePath());
503 for(size_t round
= 0; round
< 13; ++round
)
507 MUtils::OS::sleep_ms(round
);
512 QDir parent
= folder
;
517 QFile::setPermissions(folder
.absolutePath(), FILE_PERMISSIONS_NONE
);
519 parent
.rmdir(folder
.dirName());
523 if (!folder
.exists())
525 return true; /*success*/
529 qWarning("Could not rmdir \"%s\"", MUTILS_UTF8(folderPath
));
533 ///////////////////////////////////////////////////////////////////////////////
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();
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());
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
);
600 while (iter
.hasPrevious())
602 prependToPath(env
, QDir::toNativeSeparators(iter
.previous()));
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 ///////////////////////////////////////////////////////////////////////////////
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
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();
675 const QString prev
= str
;
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();
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
);
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
);
721 while (result
.endsWith(QLatin1Char('.')))
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
));
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
®exp
, quint32
&value
)
781 return regexp_parse_uint32(regexp
, &value
, 1U, 1U);
784 bool MUtils::regexp_parse_int32(const QRegExp
®exp
, qint32
&value
)
786 return regexp_parse_int32(regexp
, &value
, 1U, 1U);
789 bool MUtils::regexp_parse_uint32(const QRegExp
®exp
, quint32
&value
, const size_t &offset
)
791 return regexp_parse_uint32(regexp
, &value
, offset
, 1U);
794 bool MUtils::regexp_parse_int32(const QRegExp
®exp
, qint32
&value
, const size_t &offset
)
796 return regexp_parse_int32(regexp
, &value
, offset
, 1U);
799 bool MUtils::regexp_parse_uint32(const QRegExp
®exp
, quint32
*values
, const size_t &count
)
801 return regexp_parse_uint32(regexp
, values
, 1U, count
);
804 bool MUtils::regexp_parse_int32(const QRegExp
®exp
, qint32
*values
, const size_t &count
)
806 return regexp_parse_int32(regexp
, values
, 1U, count
);
809 bool MUtils::regexp_parse_uint32(const QRegExp
®exp
, quint32
*values
, const size_t &offset
, const size_t &count
)
811 const QStringList caps
= regexp
.capturedTexts();
813 if (caps
.isEmpty() || (quint32(caps
.count()) <= count
))
818 for (size_t i
= 0; i
< count
; i
++)
821 values
[i
] = caps
[offset
+i
].toUInt(&ok
);
831 bool MUtils::regexp_parse_int32(const QRegExp
®exp
, qint32
*values
, const size_t &offset
, const size_t &count
)
833 const QStringList caps
= regexp
.capturedTexts();
835 if (caps
.isEmpty() || (quint32(caps
.count()) <= count
))
840 for (size_t i
= 0; i
< count
; i
++)
843 values
[i
] = caps
[offset
+i
].toInt(&ok
);
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());
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
);
885 ///////////////////////////////////////////////////////////////////////////////
887 ///////////////////////////////////////////////////////////////////////////////
889 MUtils::fp_parts_t
MUtils::break_fp(const double value
)
891 fp_parts_t result
= { };
894 result
.parts
[1] = modf(value
, &result
.parts
[0]);
898 result
.parts
[0] = std::numeric_limits
<double>::quiet_NaN();
899 result
.parts
[1] = std::numeric_limits
<double>::quiet_NaN();
904 ///////////////////////////////////////////////////////////////////////////////
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: MUtils library initialization has failed!");
919 volatile int _result
= MUTILS_INTERFACE
;