331bool QCommandLineParser::addOption(
const QCommandLineOption &option)
333 const QStringList optionNames = option.names();
335 if (!optionNames.isEmpty()) {
336 for (
const QString &name : optionNames) {
337 if (d->nameHash.contains(name)) {
338 qWarning(
"QCommandLineParser: option already added: \"%ls\"", qUtf16Printable(name));
343 d->commandLineOptionList.append(option);
345 const qsizetype offset = d->commandLineOptionList.size() - 1;
346 for (
const QString &name : optionNames)
347 d->nameHash.insert(name, offset);
507QString QCommandLineParser::errorText()
const
509 if (!d->errorText.isEmpty())
511 if (d->unknownOptionNames.size() == 1)
512 return tr(
"Unknown option '%1'.").arg(d->unknownOptionNames.constFirst());
513 if (d->unknownOptionNames.size() > 1)
514 return tr(
"Unknown options: %1.").arg(d->unknownOptionNames.join(QStringLiteral(
", ")));
565[[noreturn]]
void QCommandLineParser::showMessageAndExit(MessageType type,
const QString &message,
int exitCode)
567#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
568 if (displayMessageBox()) {
569 const UINT flags = MB_OK | MB_TOPMOST | MB_SETFOREGROUND
570 | (type == MessageType::Information ? MB_ICONINFORMATION : MB_ICONERROR);
572 if (QCoreApplication::instance())
573 title = QCoreApplication::instance()->property(
"applicationDisplayName").toString();
575 title = QCoreApplication::applicationName();
576 MessageBoxW(0,
reinterpret_cast<
const wchar_t *>(message.utf16()),
577 reinterpret_cast<
const wchar_t *>(title.utf16()), flags);
578 qt_call_post_routines();
582 fputs(qPrintable(message), type == MessageType::Information ? stdout : stderr);
583 qt_call_post_routines();
601void QCommandLineParser::process(
const QStringList &arguments)
603 if (!d->parse(arguments)) {
604 showMessageAndExit(MessageType::Error,
605 QCoreApplication::applicationName() +
": "_L1 + errorText() + u'\n',
609 if (d->builtinVersionOption && isSet(QStringLiteral(
"version")))
612 if (d->builtinHelpOption && isSet(QStringLiteral(
"help")))
613 d->showHelp(EXIT_SUCCESS,
false);
615 if (d->builtinHelpOption && isSet(QStringLiteral(
"help-all")))
616 d->showHelp(EXIT_SUCCESS,
true);
666 QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd)
668 const QLatin1Char assignChar(
'=');
669 const NameHash_t::const_iterator nameHashIt =
nameHash.constFind(optionName);
670 if (nameHashIt !=
nameHash.constEnd()) {
671 const qsizetype assignPos = argument.indexOf(assignChar);
672 const NameHash_t::mapped_type optionOffset = *nameHashIt;
673 const QCommandLineOption &option = commandLineOptionList.at(optionOffset);
674 if (option.flags() & QCommandLineOption::IgnoreOptionsAfter) {
675 *argumentIterator = argsEnd;
678 const bool withValue = !option.valueName().isEmpty();
680 if (assignPos == -1) {
681 ++(*argumentIterator);
682 if (*argumentIterator == argsEnd) {
683 errorText = QCommandLineParser::tr(
"Missing value after '%1'.").arg(argument);
686 optionValuesHash[optionOffset].append(*(*argumentIterator));
688 optionValuesHash[optionOffset].append(argument.mid(assignPos + 1));
691 if (assignPos != -1) {
692 errorText = QCommandLineParser::tr(
"Unexpected value after '%1'.").arg(argument.left(assignPos));
716 const QLatin1Char dashChar(
'-');
717 const QLatin1Char assignChar(
'=');
719 bool forcePositional =
false;
721 positionalArgumentList.clear();
723 unknownOptionNames.clear();
724 optionValuesHash.clear();
726 if (args.isEmpty()) {
727 qWarning(
"QCommandLineParser: argument list cannot be empty, it should contain at least the executable name");
731 QStringList::const_iterator argumentIterator = args.begin();
734 for (; argumentIterator != args.end() ; ++argumentIterator) {
735 QString argument = *argumentIterator;
737 if (forcePositional) {
738 positionalArgumentList.append(argument);
739 }
else if (argument.startsWith(
"--"_L1)) {
740 if (argument.size() > 2) {
741 QString optionName = argument.mid(2).section(assignChar, 0, 0);
742 if (registerFoundOption(optionName)) {
743 if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
749 forcePositional =
true;
751 }
else if (argument.startsWith(dashChar)) {
752 if (argument.size() == 1) {
753 positionalArgumentList.append(argument);
756 switch (singleDashWordOptionMode) {
757 case QCommandLineParser::ParseAsCompactedShortOptions:
760 bool valueFound =
false;
761 for (
int pos = 1 ; pos < argument.size(); ++pos) {
762 optionName = argument.mid(pos, 1);
763 if (!registerFoundOption(optionName)) {
766 const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
767 Q_ASSERT(nameHashIt !=
nameHash.constEnd());
768 const NameHash_t::mapped_type optionOffset = *nameHashIt;
769 const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
771 if (pos + 1 < argument.size()) {
772 if (argument.at(pos + 1) == assignChar)
774 optionValuesHash[optionOffset].append(argument.mid(pos + 1));
779 if (pos + 1 < argument.size() && argument.at(pos + 1) == assignChar)
783 if (!valueFound && !parseOptionValue(optionName, argument, &argumentIterator, args.end()))
787 case QCommandLineParser::ParseAsLongOptions:
789 if (argument.size() > 2) {
790 const QString possibleShortOptionStyleName = argument.mid(1, 1);
791 const auto shortOptionIt =
nameHash.constFind(possibleShortOptionStyleName);
792 if (shortOptionIt !=
nameHash.constEnd()) {
793 const auto &arg = commandLineOptionList.at(*shortOptionIt);
794 if (arg.flags() & QCommandLineOption::ShortOptionStyle) {
795 registerFoundOption(possibleShortOptionStyleName);
796 optionValuesHash[*shortOptionIt].append(argument.mid(2));
801 const QString optionName = argument.mid(1).section(assignChar, 0, 0);
802 if (registerFoundOption(optionName)) {
803 if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
812 positionalArgumentList.append(argument);
813 if (optionsAfterPositionalArgumentsMode == QCommandLineParser::ParseAsPositionalArguments)
814 forcePositional =
true;
816 if (argumentIterator == args.end())
896QStringList QCommandLineParser::values(
const QString &optionName)
const
898 d->checkParsed(
"values");
899 auto it = d->nameHash.constFind(optionName);
900 if (it != d->nameHash.cend()) {
901 const qsizetype optionOffset = *it;
902 QStringList values = d->optionValuesHash.value(optionOffset);
903 if (values.isEmpty()) {
904 const auto &option = d->commandLineOptionList.at(optionOffset);
905 if (option.valueName().isEmpty()) {
906 qWarning(
"QCommandLineParser: option not expecting values: \"%ls\"",
907 qUtf16Printable(optionName));
909 values = option.defaultValues();
914 qWarning(
"QCommandLineParser: option not defined: \"%ls\"", qUtf16Printable(optionName));
915 return QStringList();
1078static QString wrapText(
const QString &names,
int optionNameMaxWidth,
const QString &description)
1080 const auto nl = u'\n';
1081 const auto indentation =
" "_L1;
1085 auto nextNameSection = [&]() {
1086 QString section = names.mid(nameIndex, optionNameMaxWidth);
1087 nameIndex += section.size();
1092 qsizetype lineStart = 0;
1093 qsizetype lastBreakable = -1;
1094 const int max = 79 - (indentation.size() + optionNameMaxWidth + 1);
1096 const qsizetype len = description.size();
1098 for (qsizetype i = 0; i < len; ++i) {
1100 const QChar c = description.at(i);
1104 qsizetype breakAt = -1;
1105 qsizetype nextLineStart = -1;
1106 if (x > max && lastBreakable != -1) {
1108 breakAt = lastBreakable;
1109 nextLineStart = lastBreakable + 1;
1110 }
else if ((x > max - 1 && lastBreakable == -1) || i == len - 1) {
1113 nextLineStart = breakAt;
1114 }
else if (c == nl) {
1117 nextLineStart = i + 1;
1120 if (breakAt != -1) {
1121 const qsizetype numChars = breakAt - lineStart;
1123 text += indentation + nextNameSection().leftJustified(optionNameMaxWidth) + u' ';
1124 text += QStringView{description}.mid(lineStart, numChars) + nl;
1127 lineStart = nextLineStart;
1128 if (lineStart < len && description.at(lineStart).isSpace())
1134 while (nameIndex < names.size()) {
1135 text += indentation + nextNameSection() + nl;
1143 const QLatin1Char nl(
'\n');
1147 usage +=
qApp ? QStringView(QCoreApplication::arguments().constFirst())
1148 : QStringView(u"<executable_name>");
1149 QList<QCommandLineOption> options = commandLineOptionList;
1150 if (includeQtOptions &&
qApp)
1151 qApp->d_func()->addQtOptions(&options);
1152 if (!options.isEmpty())
1153 usage += u' ' + QCommandLineParser::tr(
"[options]");
1154 for (
const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1155 usage += u' ' + arg.syntax;
1156 text += QCommandLineParser::tr(
"Usage: %1").arg(usage) + nl;
1157 if (!description.isEmpty())
1158 text += description + nl;
1160 if (!options.isEmpty())
1161 text += QCommandLineParser::tr(
"Options:") + nl;
1163 QStringList optionNameList;
1164 optionNameList.reserve(options.size());
1165 qsizetype longestOptionNameString = 0;
1166 for (
const QCommandLineOption &option : std::as_const(options)) {
1167 if (option.flags() & QCommandLineOption::HiddenFromHelp)
1169 const QStringList optionNames = option.names();
1170 QString optionNamesString;
1171 for (
const QString &optionName : optionNames) {
1172 const int numDashes = optionName.size() == 1 ? 1 : 2;
1173 optionNamesString += QLatin1StringView(
"--", numDashes) + optionName +
", "_L1;
1175 if (!optionNames.isEmpty())
1176 optionNamesString.chop(2);
1177 const auto valueName = option.valueName();
1178 if (!valueName.isEmpty())
1179 optionNamesString +=
" <"_L1 + valueName + u'>';
1180 optionNameList.append(optionNamesString);
1181 longestOptionNameString = qMax(longestOptionNameString, optionNamesString.size());
1184 for (
const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1185 longestOptionNameString = qMax(longestOptionNameString, arg.name.size());
1187 ++longestOptionNameString;
1188 const int optionNameMaxWidth = qMin(50,
int(longestOptionNameString));
1189 auto optionNameIterator = optionNameList.cbegin();
1190 for (
const QCommandLineOption &option : std::as_const(options)) {
1191 if (option.flags() & QCommandLineOption::HiddenFromHelp)
1193 text += wrapText(*optionNameIterator, optionNameMaxWidth, option.description());
1194 ++optionNameIterator;
1196 if (!positionalArgumentDefinitions.isEmpty()) {
1197 if (!options.isEmpty())
1199 text += QCommandLineParser::tr(
"Arguments:") + nl;
1200 for (
const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1201 text += wrapText(arg.name, optionNameMaxWidth, arg.description);
bool parseOptionValue(const QString &optionName, const QString &argument, QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd)
Parse the value for a given option, if it was defined to expect one.