File indexing completed on 2024-05-12 05:12:40

0001 /*
0002     Copyright (C) 2012  Kevin Krammer <krammer@kde.org>
0003 
0004     This program is free software; you can redistribute it and/or modify
0005     it under the terms of the GNU General Public License as published by
0006     the Free Software Foundation; either version 2 of the License, or
0007     (at your option) any later version.
0008 
0009     This program is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012     GNU General Public License for more details.
0013 
0014     You should have received a copy of the GNU General Public License along
0015     with this program; if not, write to the Free Software Foundation, Inc.,
0016     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
0017 */
0018 
0019 #include "commandfactory.h"
0020 
0021 #include "abstractcommand.h"
0022 #include "errorreporter.h"
0023 #include "commandshell.h"
0024 
0025 #include <QDebug>
0026 #include <QHash>
0027 
0028 #include <iostream>
0029 
0030 struct CommandData {
0031     KLocalizedString shortHelp;
0032     CommandFactory::creatorFunction creator;
0033 };
0034 
0035 static QHash<QString, CommandData *> *sCommands = nullptr;
0036 
0037 CommandFactory::CommandFactory(const QStringList *parsedArgs)
0038     : mParsedArgs(parsedArgs)
0039 {
0040     Q_ASSERT(mParsedArgs != nullptr);
0041 
0042     checkAndHandleHelp();
0043 }
0044 
0045 AbstractCommand *CommandFactory::createCommand()
0046 {
0047     const QString commandName = mParsedArgs->first();
0048     CommandData *data = sCommands->value(commandName);
0049     if (data == nullptr) {
0050         ErrorReporter::error(i18nc("@info:shell", "Unknown command '%1'", commandName));
0051         if (!CommandShell::isActive()) printHelpAndExit(false);
0052         return (nullptr);
0053     }
0054 
0055     AbstractCommand *command = (data->creator)(nullptr);
0056     Q_ASSERT(command != nullptr);
0057     return (command);
0058 }
0059 
0060 void CommandFactory::registerCommand(const QString &name,
0061                                      const KLocalizedString &shortHelp,
0062                                      CommandFactory::creatorFunction creator)
0063 {
0064     CommandData *data = new CommandData;
0065     data->shortHelp = shortHelp;
0066     data->creator = creator;
0067 
0068     if (sCommands == nullptr) {
0069         sCommands = new QHash<QString, CommandData *>;
0070     }
0071     sCommands->insert(name, data);
0072 }
0073 
0074 // There are 3 cases to consider here:
0075 //
0076 //  1.  No arguments specified.  Display an error message and the list of
0077 //  available commands to stderr.
0078 //
0079 //  2.  One argument specified and it is "help".  Just display the list of
0080 //  available commands to stdout.
0081 //
0082 //  3.  More than one argument is specified and the first is "help".  For
0083 //  each argument, display the help for its options to stdout.
0084 //  If there is no such command, display an error message.
0085 //
0086 // If none of the above apply, then do nothing.
0087 
0088 void CommandFactory::checkAndHandleHelp()
0089 {
0090     if (mParsedArgs->isEmpty()) {           // case 1
0091         ErrorReporter::error(i18nc("@info:shell",
0092                                    "No command specified (try '%1 --help')",
0093                                    QCoreApplication::applicationName()));
0094         std::exit(EXIT_FAILURE);
0095     }
0096 
0097     if (mParsedArgs->first() == QLatin1String("help")) {
0098         if (mParsedArgs->count() == 1) {        // case 2
0099             printHelpAndExit(true);
0100         }
0101 
0102         for (int a = 1; a<mParsedArgs->count(); ++a) {  // case 3
0103             const QString commandName = mParsedArgs->at(a);
0104             if (!sCommands->contains(commandName)) {
0105                 ErrorReporter::warning(i18nc("@info:shell", "Unknown command '%1'", commandName));
0106                 continue;
0107             }
0108 
0109             CommandData *data = sCommands->value(commandName);
0110             Q_ASSERT(data != nullptr);
0111             AbstractCommand *command = (data->creator)(nullptr);
0112             Q_ASSERT(command != nullptr);
0113             command->init(*mParsedArgs, true);      // set up and display help
0114         }
0115 
0116         if (!CommandShell::isActive()) std::exit(EXIT_SUCCESS);
0117     }
0118 }
0119 
0120 void CommandFactory::printHelpAndExit(bool userRequestedHelp)
0121 {
0122     int maxNameLength = 0;
0123     QStringList commands = sCommands->keys();
0124     std::sort(commands.begin(), commands.end());
0125     Q_FOREACH (const QString &commandName, commands) {
0126         maxNameLength = qMax(maxNameLength, commandName.length());
0127     }
0128 
0129     // if the user requested help output to stdout,
0130     // otherwise we are missing the mandatory command argument and output to stderr
0131     std::ostream &stream = userRequestedHelp ? std::cout : std::cerr;
0132 
0133     const QString linePattern = QLatin1String("  %1  %2");
0134     const bool shellActive =  CommandShell::isActive();
0135 
0136     stream << std::endl << qPrintable(i18nc("@info:shell", "Available commands are:")) << std::endl;
0137 
0138     Q_FOREACH (const QString &commandName, commands) {
0139         if (commandName == "shell" && shellActive) continue;
0140 
0141         stream << qPrintable(linePattern.arg(commandName.leftJustified(maxNameLength),
0142                                              sCommands->value(commandName)->shortHelp.toString(Kuit::TermText)))
0143                << std::endl;
0144     }
0145 
0146     if (!shellActive) std::exit(userRequestedHelp ? EXIT_SUCCESS : EXIT_FAILURE);
0147     stream << std::endl;
0148 }