8#include <qregularexpression.h>
11# include <qt_windows.h>
13# include <sys/types.h>
21#define fL1S(s) QString::fromLatin1(s)
25using namespace QMakeInternal;
27QString IoUtils::binaryAbsLocation(
const QString &argv0)
30 if (!argv0.isEmpty() && isAbsolutePath(argv0)) {
32 }
else if (argv0.contains(QLatin1Char(
'/'))
34 || argv0.contains(QLatin1Char(
'\\'))
37 ret = QDir::current().absoluteFilePath(argv0);
39 QByteArray pEnv = qgetenv(
"PATH");
40 QDir currentDir = QDir::current();
42 QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(
";"));
43 paths.prepend(QLatin1String(
"."));
45 QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(
":"));
47 for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
50 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char(
'/') + argv0);
51 if (QFile::exists(candidate)) {
58 return QDir::cleanPath(ret);
61IoUtils::FileType IoUtils::fileType(
const QString &fileName)
63 Q_ASSERT(fileName.isEmpty() || isAbsolutePath(fileName));
65 DWORD attr = GetFileAttributesW((WCHAR*)fileName.utf16());
66 if (attr == INVALID_FILE_ATTRIBUTES)
68 return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FileIsDir : FileIsRegular;
71 if (::stat(fileName.toLocal8Bit().constData(), &st))
73 return S_ISDIR(st.st_mode) ? FileIsDir : S_ISREG(st.st_mode) ? FileIsRegular : FileNotFound;
77bool IoUtils::isRelativePath(
const QString &path)
79#ifdef QMAKE_BUILTIN_PRFS
80 if (path.startsWith(QLatin1String(
":/")))
86 if (path.length() >= 3 && path.at(1) == QLatin1Char(
':') && path.at(0).isLetter()
87 && (path.at(2) == QLatin1Char(
'/') || path.at(2) == QLatin1Char(
'\\'))) {
91 if (path.length() >= 2
92 && (path.at(0).unicode() ==
'\\' || path.at(0).unicode() ==
'/')
93 && path.at(1) == path.at(0)) {
97 if (path.startsWith(QLatin1Char(
'/')))
103QStringView IoUtils::pathName(
const QString &fileName)
105 return QStringView{fileName}.left(fileName.lastIndexOf(QLatin1Char(
'/')) + 1);
108QStringView IoUtils::fileName(
const QString &fileName)
110 return QStringView(fileName).mid(fileName.lastIndexOf(QLatin1Char(
'/')) + 1);
113QString IoUtils::resolvePath(
const QString &baseDir,
const QString &fileName)
115 if (fileName.isEmpty())
117 if (isAbsolutePath(fileName))
118 return QDir::cleanPath(fileName);
120 if (fileName.at(0).unicode() ==
'/' || fileName.at(0).unicode() ==
'\\') {
121 Q_ASSERT_X(isAbsolutePath(baseDir),
"IoUtils::resolvePath", qUtf8Printable(baseDir));
122 return QDir::cleanPath(baseDir.left(2) + fileName);
125 return QDir::cleanPath(baseDir + QLatin1Char(
'/') + fileName);
131 if ((c <
sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
139 for (
int x = arg.size() - 1; x >= 0; --x) {
140 if (isSpecialChar(arg.unicode()[x].unicode(), iqm))
146QString IoUtils::shellQuoteUnix(
const QString &arg)
149 static const uchar iqm[] = {
150 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
151 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
155 return QString::fromLatin1(
"''");
158 if (hasSpecialChars(ret, iqm)) {
159 ret.replace(QLatin1Char(
'\''), QLatin1String(
"'\\''"));
160 ret.prepend(QLatin1Char(
'\''));
161 ret.append(QLatin1Char(
'\''));
166QString IoUtils::shellQuoteWin(
const QString &arg)
172 static const uchar iqm[] = {
173 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
174 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
177 static const uchar ism[] = {
178 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50,
179 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
183 return QString::fromLatin1(
"\"\"");
186 if (hasSpecialChars(ret, iqm)) {
190 ret.replace(QRegularExpression(QLatin1String(
"(\\\\*)\"")), QLatin1String(
"\\1\\1\\\""));
192 ret.replace(QRegularExpression(QLatin1String(
"(\\\\+)$")), QLatin1String(
"\\1\\1"));
198 for (
int i = 0; i < ret.size(); i++) {
199 QChar c = ret.unicode()[i];
200 if (c.unicode() ==
'"')
202 else if (!quoted && isSpecialChar(c.unicode(), ism))
203 ret.insert(i++, QLatin1Char(
'^'));
206 ret.append(QLatin1Char(
'^'));
207 ret.append(QLatin1Char(
'"'));
208 ret.prepend(QLatin1Char(
'"'));
213#if defined(PROEVALUATOR_FULL)
215# if defined(Q_OS_WIN)
216static QString windowsErrorCode()
218 wchar_t *string =
nullptr;
219 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
222 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
226 QString ret = QString::fromWCharArray(string);
227 LocalFree((HLOCAL)string);
228 return ret.trimmed();
232bool IoUtils::touchFile(
const QString &targetFileName,
const QString &referenceFileName, QString *errorString)
236 if (stat(referenceFileName.toLocal8Bit().constData(), &st)) {
237 *errorString = fL1S(
"Cannot stat() reference file %1: %2.").arg(referenceFileName, fL1S(strerror(errno)));
240# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
241 const struct timespec times[2] = { { 0, UTIME_NOW }, st.st_mtim };
242 const bool utimeError = utimensat(AT_FDCWD, targetFileName.toLocal8Bit().constData(), times, 0) < 0;
245 utb.actime = time(0);
246 utb.modtime = st.st_mtime;
247 const bool utimeError= utime(targetFileName.toLocal8Bit().constData(), &utb) < 0;
250 *errorString = fL1S(
"Cannot touch %1: %2.").arg(targetFileName, fL1S(strerror(errno)));
254 HANDLE rHand = CreateFile((
wchar_t*)referenceFileName.utf16(),
255 GENERIC_READ, FILE_SHARE_READ,
256 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
257 if (rHand == INVALID_HANDLE_VALUE) {
258 *errorString = fL1S(
"Cannot open reference file %1: %2").arg(referenceFileName, windowsErrorCode());
262 GetFileTime(rHand, NULL, NULL, &ft);
264 HANDLE wHand = CreateFile((
wchar_t*)targetFileName.utf16(),
265 GENERIC_WRITE, FILE_SHARE_READ,
266 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
267 if (wHand == INVALID_HANDLE_VALUE) {
268 *errorString = fL1S(
"Cannot open %1: %2").arg(targetFileName, windowsErrorCode());
271 SetFileTime(wHand, NULL, NULL, &ft);
277#if defined(QT_BUILD_QMAKE) && defined(Q_OS_UNIX)
278bool IoUtils::readLinkTarget(
const QString &symlinkPath, QString *target)
280 const QByteArray localSymlinkPath = QFile::encodeName(symlinkPath);
281# if defined(__GLIBC__) && !defined(PATH_MAX)
282# define PATH_CHUNK_SIZE 256
285 int size = PATH_CHUNK_SIZE;
288 s = (
char *)::realloc(s, size);
289 len = ::readlink(localSymlinkPath.constData(), s, size);
300 int len = readlink(localSymlinkPath.constData(), s, PATH_MAX);
304 *target = QFile::decodeName(QByteArray(s, len));
305# if defined(__GLIBC__) && !defined(PATH_MAX)
static bool isSpecialChar(ushort c, const uchar(&iqm)[16])
static bool hasSpecialChars(const QString &arg, const uchar(&iqm)[16])