332bool QCommandLineParser::addOption(
const QCommandLineOption &option)
334 const QStringList optionNames = option.names();
336 if (!optionNames.isEmpty()) {
337 for (
const QString &name : optionNames) {
338 if (d->nameHash.contains(name)) {
339 qWarning(
"QCommandLineParser: option already added: \"%ls\"", qUtf16Printable(name));
344 d->commandLineOptionList.append(option);
346 const qsizetype offset = d->commandLineOptionList.size() - 1;
347 for (
const QString &name : optionNames)
348 d->nameHash.insert(name, offset);
508QString QCommandLineParser::errorText()
const
510 if (!d->errorText.isEmpty())
512 if (d->unknownOptionNames.size() == 1)
513 return tr(
"Unknown option '%1'.").arg(d->unknownOptionNames.constFirst());
514 if (d->unknownOptionNames.size() > 1)
515 return tr(
"Unknown options: %1.").arg(d->unknownOptionNames.join(QStringLiteral(
", ")));
566[[noreturn]]
void QCommandLineParser::showMessageAndExit(MessageType type,
const QString &message,
int exitCode)
568#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
569 if (displayMessageBox()) {
570 const UINT flags = MB_OK | MB_TOPMOST | MB_SETFOREGROUND
571 | (type == MessageType::Information ? MB_ICONINFORMATION : MB_ICONERROR);
573 if (QCoreApplication::instance())
574 title = QCoreApplication::instance()->property(
"applicationDisplayName").toString();
576 title = QCoreApplication::applicationName();
577 MessageBoxW(0,
reinterpret_cast<
const wchar_t *>(message.utf16()),
578 reinterpret_cast<
const wchar_t *>(title.utf16()), flags);
579 qt_call_post_routines();
583 fputs(qPrintable(message), type == MessageType::Information ? stdout : stderr);
584 qt_call_post_routines();
602void QCommandLineParser::process(
const QStringList &arguments)
604 if (!d->parse(arguments)) {
605 showMessageAndExit(MessageType::Error,
606 QCoreApplication::applicationName() +
": "_L1 + errorText() + u'\n',
610 if (d->builtinVersionOption && isSet(QStringLiteral(
"version")))
613 if (d->builtinHelpOption && isSet(QStringLiteral(
"help")))
614 d->showHelp(EXIT_SUCCESS,
false);
616 if (d->builtinHelpOption && isSet(QStringLiteral(
"help-all")))
617 d->showHelp(EXIT_SUCCESS,
true);
667 QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd)
669 const QLatin1Char assignChar(
'=');
670 const NameHash_t::const_iterator nameHashIt =
nameHash.constFind(optionName);
671 if (nameHashIt !=
nameHash.constEnd()) {
672 const qsizetype assignPos = argument.indexOf(assignChar);
673 const NameHash_t::mapped_type optionOffset = *nameHashIt;
674 const QCommandLineOption &option = commandLineOptionList.at(optionOffset);
675 if (option.flags() & QCommandLineOption::IgnoreOptionsAfter) {
676 *argumentIterator = argsEnd;
679 const bool withValue = !option.valueName().isEmpty();
681 if (assignPos == -1) {
682 ++(*argumentIterator);
683 if (*argumentIterator == argsEnd) {
684 errorText = QCommandLineParser::tr(
"Missing value after '%1'.").arg(argument);
687 optionValuesHash[optionOffset].append(*(*argumentIterator));
689 optionValuesHash[optionOffset].append(argument.mid(assignPos + 1));
692 if (assignPos != -1) {
693 errorText = QCommandLineParser::tr(
"Unexpected value after '%1'.").arg(argument.left(assignPos));
717 const QLatin1Char dashChar(
'-');
718 const QLatin1Char assignChar(
'=');
720 bool forcePositional =
false;
722 positionalArgumentList.clear();
724 unknownOptionNames.clear();
725 optionValuesHash.clear();
727 if (args.isEmpty()) {
728 qWarning(
"QCommandLineParser: argument list cannot be empty, it should contain at least the executable name");
732 QStringList::const_iterator argumentIterator = args.begin();
735 for (; argumentIterator != args.end() ; ++argumentIterator) {
736 QString argument = *argumentIterator;
738 if (forcePositional) {
739 positionalArgumentList.append(argument);
740 }
else if (argument.startsWith(
"--"_L1)) {
741 if (argument.size() > 2) {
742 QString optionName = argument.mid(2).section(assignChar, 0, 0);
743 if (registerFoundOption(optionName)) {
744 if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
750 forcePositional =
true;
752 }
else if (argument.startsWith(dashChar)) {
753 if (argument.size() == 1) {
754 positionalArgumentList.append(argument);
757 switch (singleDashWordOptionMode) {
758 case QCommandLineParser::ParseAsCompactedShortOptions:
761 bool valueFound =
false;
762 for (
int pos = 1 ; pos < argument.size(); ++pos) {
763 optionName = argument.mid(pos, 1);
764 if (!registerFoundOption(optionName)) {
767 const NameHash_t::const_iterator nameHashIt =
nameHash.constFind(optionName);
768 Q_ASSERT(nameHashIt !=
nameHash.constEnd());
769 const NameHash_t::mapped_type optionOffset = *nameHashIt;
770 const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
772 if (pos + 1 < argument.size()) {
773 if (argument.at(pos + 1) == assignChar)
775 optionValuesHash[optionOffset].append(argument.mid(pos + 1));
780 if (pos + 1 < argument.size() && argument.at(pos + 1) == assignChar)
784 if (!valueFound && !parseOptionValue(optionName, argument, &argumentIterator, args.end()))
788 case QCommandLineParser::ParseAsLongOptions:
790 if (argument.size() > 2) {
791 const QString possibleShortOptionStyleName = argument.mid(1, 1);
792 const auto shortOptionIt =
nameHash.constFind(possibleShortOptionStyleName);
793 if (shortOptionIt !=
nameHash.constEnd()) {
794 const auto &arg = commandLineOptionList.at(*shortOptionIt);
795 if (arg.flags() & QCommandLineOption::ShortOptionStyle) {
796 registerFoundOption(possibleShortOptionStyleName);
797 optionValuesHash[*shortOptionIt].append(argument.mid(2));
802 const QString optionName = argument.mid(1).section(assignChar, 0, 0);
803 if (registerFoundOption(optionName)) {
804 if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
813 positionalArgumentList.append(argument);
814 if (optionsAfterPositionalArgumentsMode == QCommandLineParser::ParseAsPositionalArguments)
815 forcePositional =
true;
817 if (argumentIterator == args.end())
897QStringList QCommandLineParser::values(
const QString &optionName)
const
899 d->checkParsed(
"values");
900 auto it = d->nameHash.constFind(optionName);
901 if (it != d->nameHash.cend()) {
902 const qsizetype optionOffset = *it;
903 QStringList values = d->optionValuesHash.value(optionOffset);
904 if (values.isEmpty()) {
905 const auto &option = d->commandLineOptionList.at(optionOffset);
906 if (option.valueName().isEmpty()) {
907 qWarning(
"QCommandLineParser: option not expecting values: \"%ls\"",
908 qUtf16Printable(optionName));
910 values = option.defaultValues();
915 qWarning(
"QCommandLineParser: option not defined: \"%ls\"", qUtf16Printable(optionName));
916 return QStringList();
1079static QString wrapText(
const QString &names,
int optionNameMaxWidth,
const QString &description)
1081 const auto nl = u'\n';
1082 const auto indentation =
" "_L1;
1086 auto nextNameSection = [&]() {
1087 QString section = names.mid(nameIndex, optionNameMaxWidth);
1088 nameIndex += section.size();
1093 qsizetype lineStart = 0;
1094 qsizetype lastBreakable = -1;
1095 const int max = 79 - (indentation.size() + optionNameMaxWidth + 1);
1097 const qsizetype len = description.size();
1099 for (qsizetype i = 0; i < len; ++i) {
1101 const QChar c = description.at(i);
1105 qsizetype breakAt = -1;
1106 qsizetype nextLineStart = -1;
1107 if (x > max && lastBreakable != -1) {
1109 breakAt = lastBreakable;
1110 nextLineStart = lastBreakable + 1;
1111 }
else if ((x > max - 1 && lastBreakable == -1) || i == len - 1) {
1114 nextLineStart = breakAt;
1115 }
else if (c == nl) {
1118 nextLineStart = i + 1;
1121 if (breakAt != -1) {
1122 const qsizetype numChars = breakAt - lineStart;
1124 text += indentation + nextNameSection().leftJustified(optionNameMaxWidth) + u' ';
1125 text += QStringView{description}.mid(lineStart, numChars) + nl;
1128 lineStart = nextLineStart;
1129 if (lineStart < len && description.at(lineStart).isSpace())
1135 while (nameIndex < names.size()) {
1136 text += indentation + nextNameSection() + nl;
1144 const QLatin1Char nl(
'\n');
1148 usage +=
qApp ? QStringView(QCoreApplication::arguments().constFirst())
1149 : QStringView(u"<executable_name>");
1150 QList<QCommandLineOption> options = commandLineOptionList;
1151 if (includeQtOptions &&
qApp)
1152 qApp->d_func()->addQtOptions(&options);
1153 if (!options.isEmpty())
1154 usage += u' ' + QCommandLineParser::tr(
"[options]");
1155 for (
const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1156 usage += u' ' + arg.syntax;
1157 text += QCommandLineParser::tr(
"Usage: %1").arg(usage) + nl;
1158 if (!description.isEmpty())
1159 text += description + nl;
1161 if (!options.isEmpty())
1162 text += QCommandLineParser::tr(
"Options:") + nl;
1164 QStringList optionNameList;
1165 optionNameList.reserve(options.size());
1166 qsizetype longestOptionNameString = 0;
1167 for (
const QCommandLineOption &option : std::as_const(options)) {
1168 if (option.flags() & QCommandLineOption::HiddenFromHelp)
1170 const QStringList optionNames = option.names();
1171 QString optionNamesString;
1172 for (
const QString &optionName : optionNames) {
1173 const int numDashes = optionName.size() == 1 ? 1 : 2;
1174 optionNamesString += QLatin1StringView(
"--", numDashes) + optionName +
", "_L1;
1176 if (!optionNames.isEmpty())
1177 optionNamesString.chop(2);
1178 const auto valueName = option.valueName();
1179 if (!valueName.isEmpty())
1180 optionNamesString +=
" <"_L1 + valueName + u'>';
1181 optionNameList.append(optionNamesString);
1182 longestOptionNameString = qMax(longestOptionNameString, optionNamesString.size());
1185 for (
const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1186 longestOptionNameString = qMax(longestOptionNameString, arg.name.size());
1188 ++longestOptionNameString;
1189 const int optionNameMaxWidth = qMin(50,
int(longestOptionNameString));
1190 auto optionNameIterator = optionNameList.cbegin();
1191 for (
const QCommandLineOption &option : std::as_const(options)) {
1192 if (option.flags() & QCommandLineOption::HiddenFromHelp)
1194 text += wrapText(*optionNameIterator, optionNameMaxWidth, option.description());
1195 ++optionNameIterator;
1197 if (!positionalArgumentDefinitions.isEmpty()) {
1198 if (!options.isEmpty())
1200 text += QCommandLineParser::tr(
"Arguments:") + nl;
1201 for (
const PositionalArgumentDefinition &arg : positionalArgumentDefinitions)
1202 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.