120 static const QMakeBuiltinInit expandInits[] = {
121 {
"member", E_MEMBER, 1, 3,
"var, [start, [end]]" },
122 {
"str_member", E_STR_MEMBER, -1, 3,
"str, [start, [end]]" },
123 {
"first", E_FIRST, 1, 1,
"var" },
124 {
"take_first", E_TAKE_FIRST, 1, 1,
"var" },
125 {
"last", E_LAST, 1, 1,
"var" },
126 {
"take_last", E_TAKE_LAST, 1, 1,
"var" },
127 {
"size", E_SIZE, 1, 1,
"var" },
128 {
"str_size", E_STR_SIZE, -1, 1,
"str" },
129 {
"cat", E_CAT, 1, 2,
"file, [mode=true|blob|lines]" },
130 {
"fromfile", E_FROMFILE, 2, 2,
"file, var" },
131 {
"eval", E_EVAL, 1, 1,
"var" },
132 {
"list", E_LIST, 0, QMakeBuiltinInit::VarArgs,
nullptr },
133 {
"sprintf", E_SPRINTF, 1, QMakeBuiltinInit::VarArgs,
"format, ..." },
134 {
"format_number", E_FORMAT_NUMBER, 1, 2,
"number, [options...]" },
135 {
"num_add", E_NUM_ADD, 1, QMakeBuiltinInit::VarArgs,
"num, ..." },
136 {
"join", E_JOIN, 1, 4,
"var, [glue, [before, [after]]]" },
137 {
"split", E_SPLIT, 1, 2,
"var, sep" },
138 {
"basename", E_BASENAME, 1, 1,
"var" },
139 {
"dirname", E_DIRNAME, 1, 1,
"var" },
140 {
"section", E_SECTION, 3, 4,
"var, sep, begin, [end]" },
141 {
"find", E_FIND, 2, 2,
"var, str" },
142 {
"system", E_SYSTEM, 1, 3,
"command, [mode], [stsvar]" },
143 {
"unique", E_UNIQUE, 1, 1,
"var" },
144 {
"sorted", E_SORTED, 1, 1,
"var" },
145 {
"reverse", E_REVERSE, 1, 1,
"var" },
146 {
"quote", E_QUOTE, 0, QMakeBuiltinInit::VarArgs,
nullptr },
147 {
"escape_expand", E_ESCAPE_EXPAND, 0, QMakeBuiltinInit::VarArgs,
nullptr },
148 {
"upper", E_UPPER, 0, QMakeBuiltinInit::VarArgs,
nullptr },
149 {
"lower", E_LOWER, 0, QMakeBuiltinInit::VarArgs,
nullptr },
150 {
"title", E_TITLE, 0, QMakeBuiltinInit::VarArgs,
nullptr },
151 {
"re_escape", E_RE_ESCAPE, 0, QMakeBuiltinInit::VarArgs,
nullptr },
152 {
"val_escape", E_VAL_ESCAPE, 1, 1,
"var" },
153 {
"files", E_FILES, 1, 2,
"pattern, [recursive=false]" },
154 {
"prompt", E_PROMPT, 1, 2,
"question, [decorate=true]" },
155 {
"replace", E_REPLACE, 3, 3,
"var, before, after" },
156 {
"sort_depends", E_SORT_DEPENDS, 1, 4,
"var, [prefix, [suffixes, [prio-suffix]]]" },
157 {
"resolve_depends", E_RESOLVE_DEPENDS, 1, 4,
"var, [prefix, [suffixes, [prio-suffix]]]" },
158 {
"enumerate_vars", E_ENUMERATE_VARS, 0, 0,
"" },
159 {
"shadowed", E_SHADOWED, 1, 1,
"path" },
160 {
"absolute_path", E_ABSOLUTE_PATH, -1, 2,
"path, [base]" },
161 {
"relative_path", E_RELATIVE_PATH, -1, 2,
"path, [base]" },
162 {
"clean_path", E_CLEAN_PATH, -1, 1,
"path" },
163 {
"system_path", E_SYSTEM_PATH, -1, 1,
"path" },
164 {
"shell_path", E_SHELL_PATH, -1, 1,
"path" },
165 {
"system_quote", E_SYSTEM_QUOTE, -1, 1,
"arg" },
166 {
"shell_quote", E_SHELL_QUOTE, -1, 1,
"arg" },
167 {
"getenv", E_GETENV, 1, 1,
"arg" },
168 {
"read_registry", E_READ_REGISTRY, 2, 3,
"tree, key, [wow64]" },
170 statics.expands.reserve((
int)(
sizeof(expandInits)/
sizeof(expandInits[0])));
171 for (
unsigned i = 0; i <
sizeof(expandInits)/
sizeof(expandInits[0]); ++i)
172 statics.expands.insert(ProKey(expandInits[i].name), QMakeBuiltin(expandInits[i]));
174 static const QMakeBuiltinInit testInits[] = {
175 {
"requires", T_REQUIRES, 0, QMakeBuiltinInit::VarArgs,
nullptr },
176 {
"greaterThan", T_GREATERTHAN, 2, 2,
"var, val" },
177 {
"lessThan", T_LESSTHAN, 2, 2,
"var, val" },
178 {
"equals", T_EQUALS, 2, 2,
"var, val" },
179 {
"isEqual", T_EQUALS, 2, 2,
"var, val" },
180 {
"versionAtLeast", T_VERSION_AT_LEAST, 2, 2,
"var, version" },
181 {
"versionAtMost", T_VERSION_AT_MOST, 2, 2,
"var, version" },
182 {
"exists", T_EXISTS, 1, 1,
"file" },
183 {
"export", T_EXPORT, 1, 1,
"var" },
184 {
"clear", T_CLEAR, 1, 1,
"var" },
185 {
"unset", T_UNSET, 1, 1,
"var" },
186 {
"eval", T_EVAL, 0, QMakeBuiltinInit::VarArgs,
nullptr },
187 {
"CONFIG", T_CONFIG, 1, 2,
"config, [mutuals]" },
188 {
"if", T_IF, 1, 1,
"condition" },
189 {
"isActiveConfig", T_CONFIG, 1, 2,
"config, [mutuals]" },
190 {
"system", T_SYSTEM, 1, 1,
"exec" },
191 {
"discard_from", T_DISCARD_FROM, 1, 1,
"file" },
192 {
"defined", T_DEFINED, 1, 2,
"object, [\"test\"|\"replace\"|\"var\"]" },
193 {
"contains", T_CONTAINS, 2, 3,
"var, val, [mutuals]" },
194 {
"infile", T_INFILE, 2, 3,
"file, var, [values]" },
195 {
"count", T_COUNT, 2, 3,
"var, count, [op=operator]" },
196 {
"isEmpty", T_ISEMPTY, 1, 1,
"var" },
197 {
"parseJson", T_PARSE_JSON, 2, 2,
"var, into" },
198 {
"load", T_LOAD, 1, 2,
"feature, [ignore_errors=false]" },
199 {
"include", T_INCLUDE, 1, 3,
"file, [into, [silent]]" },
200 {
"debug", T_DEBUG, 2, 2,
"level, message" },
201 {
"log", T_LOG, 1, 1,
"message" },
202 {
"message", T_MESSAGE, 1, 1,
"message" },
203 {
"warning", T_WARNING, 1, 1,
"message" },
204 {
"error", T_ERROR, 0, 1,
"message" },
205 {
"mkpath", T_MKPATH, 1, 1,
"path" },
206 {
"write_file", T_WRITE_FILE, 1, 3,
"name, [content var, [append] [exe]]" },
207 {
"touch", T_TOUCH, 2, 2,
"file, reffile" },
208 {
"cache", T_CACHE, 0, 3,
"[var], [set|add|sub] [transient] [super|stash], [srcvar]" },
209 {
"reload_properties", T_RELOAD_PROPERTIES, 0, 0,
"" },
211 statics.functions.reserve((
int)(
sizeof(testInits)/
sizeof(testInits[0])));
212 for (
unsigned i = 0; i <
sizeof(testInits)/
sizeof(testInits[0]); ++i)
213 statics.functions.insert(ProKey(testInits[i].name), QMakeBuiltin(testInits[i]));
576 int asz = args.size() > 1 ? args.size() : args.at(0).isEmpty() ? 0 : 1;
577 if (asz < adef.minArgs || asz > adef.maxArgs) {
582 int func_t = adef.index;
592 if (func_t == E_SECTION) {
594 sep = args.at(1).toQString();
595 beg = args.at(2).toInt();
596 if (args.size() == 4)
597 end = args.at(3).toInt();
601 sep = QLatin1String(
"[\\\\/]");
602 if (func_t == E_DIRNAME)
610 QRegularExpression sepRx(sep, QRegularExpression::DotMatchesEverythingOption);
611 if (!sepRx.isValid()) {
612 evalError(
fL1S(
"section(): Encountered invalid regular expression '%1'.").arg(sep));
615 for (
const ProString &str : strings) {
616 ProStringRwUser u1(str, m_tmp[m_toggle ^= 1]);
617 ret << u1.extract(u1.str().section(sepRx, beg, end));
620 for (
const ProString &str : strings) {
621 ProStringRwUser u1(str, m_tmp1);
622 ret << u1.extract(u1.str().section(sep, beg, end));
630 QString tmp = u1.str();
631 for (
int i = 1; i < args.size(); ++i)
632 tmp = tmp.arg(args.at(i).toQStringView());
633 ret << u1.extract(tmp);
636 case E_FORMAT_NUMBER: {
640 bool zeropad =
false;
641 bool leftalign =
false;
642 enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign;
643 if (args.size() >= 2) {
644 const auto opts = split_value_list(args.at(1).toQStringView());
645 for (
const ProString &opt : opts) {
646 if (opt.startsWith(QLatin1String(
"ibase="))) {
647 ibase = opt.mid(6).toInt();
648 }
else if (opt.startsWith(QLatin1String(
"obase="))) {
649 obase = opt.mid(6).toInt();
650 }
else if (opt.startsWith(QLatin1String(
"width="))) {
651 width = opt.mid(6).toInt();
652 }
else if (opt == QLatin1String(
"zeropad")) {
654 }
else if (opt == QLatin1String(
"padsign")) {
656 }
else if (opt == QLatin1String(
"alwayssign")) {
658 }
else if (opt == QLatin1String(
"leftalign")) {
661 evalError(
fL1S(
"format_number(): invalid format option %1.")
662 .arg(opt.toQStringView()));
667 if (args.at(0).contains(QLatin1Char(
'.'))) {
668 evalError(
fL1S(
"format_number(): floats are currently not supported."));
672 qlonglong num = args.at(0).toLongLong(&ok, ibase);
674 evalError(
fL1S(
"format_number(): malformed number %2 for base %1.")
675 .arg(ibase).arg(args.at(0).toQStringView()));
681 outstr = QLatin1Char(
'-');
682 }
else if (sign == AlwaysSign) {
683 outstr = QLatin1Char(
'+');
684 }
else if (sign == PadSign) {
685 outstr = QLatin1Char(
' ');
687 QString numstr = QString::number(num, obase);
688 int space = width - outstr.size() - numstr.size();
691 }
else if (leftalign) {
692 outstr += numstr + QString(space, QLatin1Char(
' '));
693 }
else if (zeropad) {
694 outstr += QString(space, QLatin1Char(
'0')) + numstr;
696 outstr.prepend(QString(space, QLatin1Char(
' ')));
704 for (
const ProString &arg : std::as_const(args)) {
705 if (arg.contains(QLatin1Char(
'.'))) {
706 evalError(
fL1S(
"num_add(): floats are currently not supported."));
710 qlonglong num = arg.toLongLong(&ok);
712 evalError(
fL1S(
"num_add(): malformed number %1.")
713 .arg(arg.toQStringView()));
718 ret += ProString(QString::number(sum));
723 if (args.size() >= 2)
725 if (args.size() >= 3)
727 if (args.size() == 4)
730 if (!var.isEmpty()) {
732 for (
const ProString &v : var)
733 if (
int s = v.sourceFile()) {
743 const QString &sep = (args.size() == 2) ? u1.set(args.at(1)) : statics.field_sep;
744 const auto vars =
values(map(args.at(0))
);
745 for (
const ProString &var : vars) {
747 const auto splits = var.toQStringView().split(sep, Qt::KeepEmptyParts);
748 for (
const auto &splt : splits)
749 ret << ProString(splt).setSource(var);
757 ret.reserve(qAbs(end - start) + 1);
759 for (
int i = start; i <= end && src.size() >= i; i++)
762 for (
int i = start; i >= end && src.size() >= i && i >= 0; i--)
773 res.reserve(qAbs(end - start) + 1);
775 for (
int i = start; i <= end && src
.size() >= i; i++)
778 for (
int i = start; i >= end && src
.size() >= i && i >= 0; i--)
788 if (!var.isEmpty()) {
789 if (func_t == E_FIRST)
792 ret.append(var.last());
799 if (!var.isEmpty()) {
800 if (func_t == E_TAKE_FIRST)
801 ret.append(var.takeFirst());
803 ret.append(var.takeLast());
808 ret.append(ProString(QString::number(values(map(args.at(0))).size())));
811 ret.append(ProString(QString::number(args.at(0).size())));
816 bool singleLine =
true;
817 if (args.size() > 1) {
818 if (!args.at(1).compare(QLatin1String(
"false"), Qt::CaseInsensitive))
820 else if (!args.at(1).compare(QLatin1String(
"blob"), Qt::CaseInsensitive))
822 else if (!args.at(1).compare(QLatin1String(
"lines"), Qt::CaseInsensitive))
825 QString fn = filePathEnvArg0(args);
827 if (qfile.open(QIODevice::ReadOnly)) {
828 QTextStream stream(&qfile);
832 while (!stream.atEnd()) {
836 const QString &line = stream.readLine();
837 ret += split_value_list(QStringView(line).trimmed());
848 QString fn = filePathEnvArg0(args);
849 if (evaluateFileInto(fn, &vars, LoadProOnly) == ReturnTrue)
850 ret = vars.value(map(args.at(1)));
857 QString tmp(QString::asprintf(
".QMAKE_INTERNAL_TMP_variableName_%d", m_listCount++));
860 for (
const ProString &arg : args)
861 lst += split_value_list(arg.toQStringView(), arg.sourceFile());
865 QRegularExpression regx(args.at(1).toQString(), QRegularExpression::DotMatchesEverythingOption);
866 if (!regx.isValid()) {
867 evalError(
fL1S(
"find(): Encountered invalid regular expression '%1'.").arg(regx.pattern()));
870 const auto vals =
values(map(args.at(0))
);
871 for (
const ProString &val : vals) {
872 ProStringRoUser u1(val, m_tmp[m_toggle ^= 1]);
873 if (u1.str().contains(regx))
883 bool singleLine =
true;
884 if (args.size() > 1) {
885 if (!args.at(1).compare(QLatin1String(
"false"), Qt::CaseInsensitive))
887 else if (!args.at(1).compare(QLatin1String(
"blob"), Qt::CaseInsensitive))
889 else if (!args.at(1).compare(QLatin1String(
"lines"), Qt::CaseInsensitive))
893 QByteArray bytes = getCommandOutput(args.at(0).toQString(), &exitCode);
894 if (args.size() > 2 && !args.at(2).isEmpty()) {
895 m_valuemapStack.top()[args.at(2).toKey()] =
896 ProStringList(ProString(QString::number(exitCode)));
899 QTextStream stream(bytes);
900 while (!stream.atEnd())
903 QString output = QString::fromLocal8Bit(bytes);
907 output.replace(QLatin1Char(
'\t'), QLatin1Char(
' '));
909 output.replace(QLatin1Char(
'\n'), QLatin1Char(
' '));
910 ret += split_value_list(QStringView(output));
921 std::sort(ret.begin(), ret.end());
925 for (
int i = 0; i < var.size() / 2; i++)
926 qSwap(var[i], var[var.size() - i - 1]);
933 case E_ESCAPE_EXPAND:
934 for (
int i = 0; i < args.size(); ++i) {
935 QString str = args.at(i).toQString();
936 QChar *i_data = str.data();
937 int i_len = str.size();
938 for (
int x = 0; x < i_len; ++x) {
939 if (*(i_data+x) == QLatin1Char(
'\\') && x < i_len-1) {
940 if (*(i_data+x+1) == QLatin1Char(
'\\')) {
945 } mapped_quotes[] = {
951 for (
int i = 0; mapped_quotes[i].in; ++i) {
952 if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) {
953 *(i_data+x) = QLatin1Char(mapped_quotes[i].out);
955 memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*
sizeof(QChar));
963 ret.append(
ProString(QString(i_data, i_len)).setSource(args.at(i)));
967 for (
int i = 0; i < args.size(); ++i) {
969 ret << u1.extract(QRegularExpression::escape(u1.str()));
974 ret.reserve(vals.size());
975 for (
const ProString &str : vals)
976 ret += ProString(quoteValue(str));
982 for (
int i = 0; i < args.size(); ++i) {
984 QString rstr = u1.str();
985 if (func_t == E_UPPER) {
986 rstr = rstr.toUpper();
988 rstr = rstr.toLower();
989 if (func_t == E_TITLE && rstr.size() > 0)
990 rstr[0] = rstr.at(0).toTitleCase();
992 ret << u1.extract(rstr);
996 bool recursive =
false;
997 if (args.size() == 2)
998 recursive = isTrue(args.at(1));
1001 QString r = m_option->expandEnvVars(u1.str())
1002 .replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
1004 if (IoUtils::isRelativePath(r)) {
1006 if (!pfx.endsWith(QLatin1Char(
'/')))
1007 pfx += QLatin1Char(
'/');
1009 int slash = r.lastIndexOf(QLatin1Char(
'/'));
1011 dirs.append(r.left(slash+1));
1014 dirs.append(QString());
1017 QString pattern = QRegularExpression::wildcardToRegularExpression(r);
1018 QRegularExpression regex(pattern, QRegularExpression::DotMatchesEverythingOption);
1019 if (!regex.isValid()) {
1020 evalError(
fL1S(
"section(): Encountered invalid wildcard expression '%1'.").arg(pattern));
1023 for (
int d = 0; d < dirs.size(); d++) {
1024 QString dir = dirs[d];
1025 QDir qdir(pfx + dir);
1026 for (
int i = 0, count =
int(qdir.count()); i < count; ++i) {
1027 if (qdir[i] == statics.strDot || qdir[i] == statics.strDotDot)
1029 QString fname = dir + qdir[i];
1030 if (IoUtils::fileType(pfx + fname) == IoUtils::FileIsDir) {
1032 dirs.append(fname + QLatin1Char(
'/'));
1034 if (regex.match(qdir[i]).hasMatch())
1040#ifdef PROEVALUATOR_FULL
1042 ProStringRoUser u1(args.at(0), m_tmp1);
1043 QString msg = m_option->expandEnvVars(u1.str());
1044 bool decorate =
true;
1045 if (args.count() == 2)
1046 decorate = isTrue(args.at(1));
1048 if (!msg.endsWith(QLatin1Char(
'?')))
1049 msg += QLatin1Char(
'?');
1050 fprintf(stderr,
"Project PROMPT: %s ", qPrintable(msg));
1052 fputs(qPrintable(msg), stderr);
1055 if (qfile.open(stdin, QIODevice::ReadOnly)) {
1056 QTextStream t(&qfile);
1057 const QString &line = t.readLine();
1059 fputs(
"\n", stderr);
1060 evalError(fL1S(
"Unexpected EOF."));
1063 ret = split_value_list(QStringView(line));
1069 const QRegularExpression before(args.at(1).toQString(), QRegularExpression::DotMatchesEverythingOption);
1070 if (!before.isValid()) {
1071 evalError(
fL1S(
"replace(): Encountered invalid regular expression '%1'.").arg(before.pattern()));
1075 const QString &after = u2
.str();
1076 const auto vals =
values(map(args.at(0))
);
1077 for (
const ProString &val : vals) {
1078 ProStringRwUser u1(val, m_tmp1);
1079 QString rstr = u1.str();
1080 QString copy = rstr;
1081 rstr.replace(before, after);
1082 ret << u1.extract(rstr, u2);
1086 case E_SORT_DEPENDS:
1087 case E_RESOLVE_DEPENDS: {
1088 QHash<ProKey, QSet<ProKey> > dependencies;
1090 QMultiMap<
int, ProString> rootSet;
1094 populateDeps(orgList, prefix,
1095 args.size() < 3 ? ProStringList(ProString(
".depends"))
1096 : split_value_list(args.at(2).toQStringView()),
1097 priosfx, dependencies, dependees, rootSet);
1098 while (!rootSet.isEmpty()) {
1099 QMultiMap<
int, ProString>::iterator it = rootSet.begin();
1102 if ((func_t == E_RESOLVE_DEPENDS) || orgList.contains(item))
1104 for (
const ProString &dep : std::as_const(dependees[item.toKey()])) {
1105 QSet<ProKey> &dset = dependencies[dep.toKey()];
1106 dset.remove(item.toKey());
1108 rootSet.insert(first(ProKey(prefix + dep + priosfx)).toInt(), dep);
1113 case E_ENUMERATE_VARS: {
1114 QSet<ProString> keys;
1115 for (
const ProValueMap &vmap : std::as_const(m_valuemapStack))
1116 for (ProValueMap::ConstIterator it = vmap.constBegin(); it != vmap.constEnd(); ++it)
1117 keys.insert(it.key());
1118 ret.reserve(keys.size());
1119 for (
const ProString &key : std::as_const(keys))
1124 QString rstr = m_option->shadowedPath(resolvePath(u1.str()));
1125 if (!rstr.isEmpty())
1126 ret << u1.extract(rstr);
1129 case E_ABSOLUTE_PATH: {
1132 QString baseDir = args.size() > 1
1133 ? IoUtils::resolvePath(currentDirectory(), u2.set(args.at(1)))
1134 : currentDirectory();
1135 QString rstr = u1.str().isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, u1.str());
1136 ret << u1.extract(rstr, u2);
1139 case E_RELATIVE_PATH: {
1142 QString baseDir = args.size() > 1
1143 ? IoUtils::resolvePath(currentDirectory(), u2.set(args.at(1)))
1144 : currentDirectory();
1145 QString absArg = u1.str().isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, u1.str());
1146 QString rstr = QDir(baseDir).relativeFilePath(absArg);
1147 ret << u1.extract(rstr);
1150 case E_CLEAN_PATH: {
1152 ret << u1.extract(QDir::cleanPath(u1.str()));
1155 case E_SYSTEM_PATH: {
1157 QString rstr = u1.str();
1159 rstr.replace(QLatin1Char(
'/'), QLatin1Char(
'\\'));
1161 rstr.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
1163 ret << u1.extract(rstr);
1166 case E_SHELL_PATH: {
1168 QString rstr = u1.str();
1169 if (m_dirSep.startsWith(QLatin1Char(
'\\'))) {
1170 rstr.replace(QLatin1Char(
'/'), QLatin1Char(
'\\'));
1172 rstr.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
1175 if (rstr.length() > 2 && rstr.at(1) == QLatin1Char(
':') && rstr.at(2) == QLatin1Char(
'/')) {
1176 rstr[1] = rstr.at(0);
1177 rstr[0] = QLatin1Char(
'/');
1181 ret << u1.extract(rstr);
1184 case E_SYSTEM_QUOTE: {
1186 ret << u1.extract(IoUtils::shellQuote(u1.str()));
1189 case E_SHELL_QUOTE: {
1191 QString rstr = u1.str();
1192 if (m_dirSep.startsWith(QLatin1Char(
'\\')))
1193 rstr = IoUtils::shellQuoteWin(rstr);
1195 rstr = IoUtils::shellQuoteUnix(rstr);
1196 ret << u1.extract(rstr);
1205 case E_READ_REGISTRY: {
1207 const auto par = args.at(0);
1208 if (!par.compare(QLatin1String(
"HKCU"), Qt::CaseInsensitive)
1209 || !par.compare(QLatin1String(
"HKEY_CURRENT_USER"), Qt::CaseInsensitive)) {
1210 tree = HKEY_CURRENT_USER;
1211 }
else if (!par.compare(QLatin1String(
"HKLM"), Qt::CaseInsensitive)
1212 || !par.compare(QLatin1String(
"HKEY_LOCAL_MACHINE"), Qt::CaseInsensitive)) {
1213 tree = HKEY_LOCAL_MACHINE;
1215 evalError(fL1S(
"read_registry(): invalid or unsupported registry tree %1.")
1216 .arg(par.toQStringView()));
1220 if (args.count() > 2) {
1221 const auto opt = args.at(2);
1223 || !opt.compare(QLatin1String(
"wow64_32key"), Qt::CaseInsensitive)) {
1224 flags = KEY_WOW64_32KEY;
1225 }
else if (opt ==
"64"
1226 || !opt.compare(QLatin1String(
"wow64_64key"), Qt::CaseInsensitive)) {
1227 flags = KEY_WOW64_64KEY;
1229 evalError(fL1S(
"read_registry(): invalid option %1.")
1230 .arg(opt.toQStringView()));
1234 ret << ProString(qt_readRegistryKey(tree, args.at(1).toQString(m_tmp1), flags));
1239 evalError(
fL1S(
"Function '%1' is not implemented.").arg(func.toQStringView()));
1416 int asz = args.size() > 1 ? args.size() : args.at(0).isEmpty() ? 0 : 1;
1425 const ProKey &var = args.at(0).toKey();
1426 if (args.size() > 1) {
1427 if (args[1] == QLatin1String(
"test")) {
1428 return returnBool(m_functionDefs.testFunctions.contains(var));
1429 }
else if (args[1] == QLatin1String(
"replace")) {
1430 return returnBool(m_functionDefs.replaceFunctions.contains(var));
1431 }
else if (args[1] == QLatin1String(
"var")) {
1432 ProValueMap::Iterator it;
1435 evalError(
fL1S(
"defined(function, type): unexpected type [%1].")
1436 .arg(args.at(1).toQStringView()));
1439 return returnBool(m_functionDefs.replaceFunctions.contains(var)
1440 || m_functionDefs.testFunctions.contains(var));
1443 const ProKey &var = map(args.at(0));
1446 ProValueMap::Iterator it = (*vmi).find(var);
1447 if (it != (*vmi).end()) {
1448 if (it->constBegin() == statics.fakeValue.constBegin()) {
1464 evalError(
fL1S(
"discard_from() cannot be called from functions."));
1468 QString fn = resolvePath(u1.str());
1469 QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
1470 int pro =
m_vfs->idForFileName(fn, flags | QMakeVfs::VfsAccessedOnly);
1474 for (
auto vit = vmap.begin(); vit != vmap.end(); ) {
1475 if (!vit->isEmpty()) {
1476 auto isFrom = [pro](
const ProString &s) {
1477 return s.sourceFile() == pro;
1479 vit->removeIf(isFrom);
1480 if (vit->isEmpty()) {
1483 vit = vmap.erase(vit);
1489 for (
auto fit = m_functionDefs.testFunctions.begin(); fit != m_functionDefs.testFunctions.end(); ) {
1490 if (fit->pro()->id() == pro)
1491 fit = m_functionDefs.testFunctions.erase(fit);
1495 for (
auto fit = m_functionDefs.replaceFunctions.begin(); fit != m_functionDefs.replaceFunctions.end(); ) {
1496 if (fit->pro()->id() == pro)
1497 fit = m_functionDefs.replaceFunctions.erase(fit);
1509 QString fn = filePathEnvArg0(args);
1510 VisitReturn ok = evaluateFileInto(fn, &vars, LoadProOnly);
1513 if (args.size() == 2)
1515 QRegularExpression regx;
1516 regx.setPatternOptions(QRegularExpression::DotMatchesEverythingOption);
1518 const QString &qry = u1
.str();
1519 if (qry != QRegularExpression::escape(qry)) {
1520 regx.setPattern(QRegularExpression::anchoredPattern(qry));
1521 if (!regx.isValid()) {
1522 evalError(
fL1S(
"infile(): Encountered invalid regular expression '%1'.").arg(qry));
1526 const auto strings = vars.value(map(args.at(1)));
1527 for (
const ProString &s : strings) {
1530 if (!regx.pattern().isEmpty()) {
1531 ProStringRoUser u2(s, m_tmp[m_toggle ^= 1]);
1532 if (regx.match(u2.str()).hasMatch())
1539#ifdef PROEVALUATOR_FULL
1540 if (checkRequirements(args) == ReturnError)
1546 QString contents = args.join(statics.field_sep);
1550 m_locationStack.push(m_current);
1553 m_current = m_locationStack.pop();
1559 return evaluateConditional(args.at(0).toQStringView(),
1560 m_current.pro->fileName(), m_current.line);
1563 if (args.size() == 1)
1564 return returnBool(isActiveConfig(args.at(0).toQStringView()));
1565 const auto mutuals = args.at(1).toQStringView().split(QLatin1Char(
'|'),
1566 Qt::SkipEmptyParts);
1569 for (
int i = configs.size() - 1; i >= 0; i--) {
1570 for (
int mut = 0; mut < mutuals.size(); mut++) {
1571 if (configs[i].toQStringView() == mutuals[mut].trimmed())
1579 const QString &qry = u1
.str();
1580 QRegularExpression regx;
1581 regx.setPatternOptions(QRegularExpression::DotMatchesEverythingOption);
1582 if (qry != QRegularExpression::escape(qry)) {
1583 regx.setPattern(QRegularExpression::anchoredPattern(qry));
1584 if (!regx.isValid()) {
1585 evalError(
fL1S(
"contains(): Encountered invalid regular expression '%1'.").arg(qry));
1590 if (args.size() == 2) {
1591 for (
int i = 0; i < l.size(); ++i) {
1595 if (!regx.pattern().isEmpty()) {
1597 if (regx.match(u2
.str()).hasMatch())
1602 const auto mutuals = args.at(2).toQStringView().split(QLatin1Char(
'|'),
1603 Qt::SkipEmptyParts);
1604 for (
int i = l.size() - 1; i >= 0; i--) {
1606 for (
int mut = 0; mut < mutuals.size(); mut++) {
1607 if (val.toQStringView() == mutuals[mut].trimmed()) {
1610 if (!regx.pattern().isEmpty()) {
1612 if (regx.match(u2
.str()).hasMatch())
1623 int cnt =
values(map(args.at(0))
).size();
1624 int val = args.at(1).toInt();
1625 if (args.size() == 3) {
1627 if (comp == QLatin1String(
">") || comp == QLatin1String(
"greaterThan")) {
1629 }
else if (comp == QLatin1String(
">=")) {
1631 }
else if (comp == QLatin1String(
"<") || comp == QLatin1String(
"lessThan")) {
1633 }
else if (comp == QLatin1String(
"<=")) {
1635 }
else if (comp == QLatin1String(
"equals") || comp == QLatin1String(
"isEqual")
1636 || comp == QLatin1String(
"=") || comp == QLatin1String(
"==")) {
1639 evalError(
fL1S(
"Unexpected modifier to count(%2).").arg(comp.toQStringView()));
1648 const QString &lhs =
values(map(args.at(0))
).join(statics.field_sep);
1652 int lhs_int = lhs.toInt(&ok);
1665 == args.at(1).toQStringView()
);
1668 const QVersionNumber lvn = QVersionNumber::fromString(values(args.at(0).toKey()).join(QLatin1Char(
'.')));
1669 const QVersionNumber rvn = QVersionNumber::fromString(args.at(1).toQStringView());
1676 ProValueMap::Iterator it;
1677 const ProKey &var = map(args.at(0));
1678 if (!(hsh = findValues(var, &it)))
1683 m_valuemapStack.top()[var].clear();
1688 ProValueMap::Iterator it;
1689 const ProKey &var = map(args.at(0));
1690 if (!(hsh = findValues(var, &it)))
1694 else if (hsh == &m_valuemapStack.top())
1695 *it = statics.fakeValue;
1697 m_valuemapStack.top()[var] = statics.fakeValue;
1701 QByteArray json = values(args.at(0).toKey()).join(QLatin1Char(
' ')).toUtf8();
1703 QString parseInto = u1.str();
1711 if (args.size() >= 2) {
1712 if (!args.at(1).isEmpty())
1713 parseInto = args.at(1) + QLatin1Char(
'.');
1714 if (args.size() >= 3 && isTrue(args.at(2)))
1717 QString fn = filePathEnvArg0(args);
1719 if (parseInto.isEmpty()) {
1720 ok = evaluateFileChecked(fn, QMakeHandler::EvalIncludeFile, LoadProOnly | flags);
1723 if ((ok = evaluateFileInto(fn, &symbols, LoadAll | flags)) == ReturnTrue) {
1725 for (ProValueMap::ConstIterator
1727 end = m_valuemapStack.top().constEnd();
1729 const ProString &ky = it.key();
1730 if (!ky.startsWith(parseInto))
1731 newMap[it.key()] = it.value();
1733 for (ProValueMap::ConstIterator it = symbols.constBegin();
1734 it != symbols.constEnd(); ++it) {
1735 if (!it.key().startsWith(QLatin1Char(
'.')))
1736 newMap.insert(ProKey(parseInto + it.key()), it.value());
1738 m_valuemapStack.top() = newMap;
1741 if (ok == ReturnFalse && (flags & LoadSilent))
1746 bool ignore_error = (args.size() == 2 && isTrue(args.at(1)));
1754#ifdef PROEVALUATOR_DEBUG
1755 int level = args.at(0).toInt();
1756 if (level <= m_debugLevel) {
1757 ProStringRoUser u1(args.at(1), m_tmp1);
1758 const QString &msg = m_option->expandEnvVars(u1.str());
1759 debugMsg(level,
"Project DEBUG: %s", qPrintable(msg));
1771 if (func_t ==
T_LOG) {
1772#ifdef PROEVALUATOR_FULL
1773 fputs(msg.toLatin1().constData(), stderr);
1775 }
else if (!msg.isEmpty() || func_t !=
T_ERROR) {
1782 fL1S(
"Project %1: %2").arg(u2.str().toUpper(), msg));
1788#ifdef PROEVALUATOR_FULL
1791#if QT_CONFIG(process)
1793 proc.setProcessChannelMode(QProcess::ForwardedChannels);
1794 runProcess(&proc, args.at(0).toQString());
1795 return returnBool(proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0);
1797 int ec = system((QLatin1String(
"cd ")
1798 + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory()))
1799 + QLatin1String(
" && ") + args.at(0)).toLocal8Bit().constData());
1801 if (ec != -1 && WIFSIGNALED(ec) && (WTERMSIG(ec) == SIGQUIT || WTERMSIG(ec) == SIGINT))
1802 raise(WTERMSIG(ec));
1804 return returnBool(ec == 0);
1814 QString file = filePathEnvArg0(args);
1818 if (IoUtils::exists(file))
1820 int slsh = file.lastIndexOf(QLatin1Char(
'/'));
1821 QString fn = file.mid(slsh+1);
1822 if (fn.contains(QLatin1Char(
'*')) || fn.contains(QLatin1Char(
'?'))) {
1823 QString dirstr = file.left(slsh+1);
1825 if (!QDir(dirstr).entryList(QStringList(fn)).isEmpty())
1832#ifdef PROEVALUATOR_FULL
1833 QString fn = filePathArg0(args);
1834 if (!QDir::current().mkpath(fn)) {
1835 evalError(fL1S(
"Cannot create directory %1.").arg(QDir::toNativeSeparators(fn)));
1842 QIODevice::OpenMode mode = QIODevice::Truncate;
1843 QMakeVfs::VfsFlags flags = (m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
1845 if (args.size() >= 2) {
1847 if (!vals.isEmpty())
1848 contents = vals.join(QLatin1Char(
'\n')) + QLatin1Char(
'\n');
1849 if (args.size() >= 3) {
1850 const auto opts = split_value_list(args.at(2).toQStringView());
1851 for (
const ProString &opt : opts) {
1852 if (opt == QLatin1String(
"append")) {
1853 mode = QIODevice::Append;
1854 }
else if (opt == QLatin1String(
"exe")) {
1855 flags |= QMakeVfs::VfsExecutable;
1857 evalError(
fL1S(
"write_file(): invalid flag %1.").arg(opt.toQStringView()));
1863 QString path = filePathArg0(args);
1864 return writeFile(QString(), path, mode, flags, contents);
1867#ifdef PROEVALUATOR_FULL
1868 ProStringRoUser u1(args.at(0), m_tmp1);
1869 ProStringRoUser u2(args.at(1), m_tmp2);
1870 const QString &tfn = resolvePath(u1.str());
1871 const QString &rfn = resolvePath(u2.str());
1873 if (!IoUtils::touchFile(tfn, rfn, &error)) {
1881 return testFunc_cache(args);
1883#ifdef QT_BUILD_QMAKE
1884 m_option->reloadProperties();
1888 evalError(
fL1S(
"Function '%1' is not implemented.").arg(function.toQStringView()));