diff options
Diffstat (limited to 'depends/util')
-rw-r--r-- | depends/util/CMakeLists.txt | 61 | ||||
-rw-r--r-- | depends/util/include/cmdutils.h | 255 | ||||
-rw-r--r-- | depends/util/include/libutil_config.h | 28 | ||||
-rw-r--r-- | depends/util/include/osutils.h | 26 | ||||
-rw-r--r-- | depends/util/include/pathutils.h | 59 | ||||
-rw-r--r-- | depends/util/include/userutils.h | 17 | ||||
-rw-r--r-- | depends/util/src/cmdutils.cpp | 486 | ||||
-rw-r--r-- | depends/util/src/pathutils.cpp | 147 | ||||
-rw-r--r-- | depends/util/src/userutils.cpp | 127 |
9 files changed, 1206 insertions, 0 deletions
diff --git a/depends/util/CMakeLists.txt b/depends/util/CMakeLists.txt new file mode 100644 index 00000000..db7d70e6 --- /dev/null +++ b/depends/util/CMakeLists.txt @@ -0,0 +1,61 @@ +project(libUtil) + +######## Set compiler flags ######## +IF(APPLE) + # assume clang 4.1.0+, add C++0x/C++11 stuff + message(STATUS "Using APPLE CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +ELSEIF(UNIX) + # assume GCC, add C++0x/C++11 stuff + MESSAGE(STATUS "Using UNIX CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +ELSEIF(MINGW) + MESSAGE(STATUS "Using MINGW CMAKE_CXX_FLAGS") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") +ENDIF() + + +# Find Qt +find_package(Qt5Core REQUIRED) + +# Include Qt headers. +include_directories(${Qt5Base_INCLUDE_DIRS}) +# include_directories(${Qt5Network_INCLUDE_DIRS}) + +SET(LIBUTIL_SOURCES +include/libutil_config.h + +include/pathutils.h +src/pathutils.cpp + +include/osutils.h + +include/userutils.h +src/userutils.cpp + +include/cmdutils.h +src/cmdutils.cpp +) + +# Set the include dir path. +SET(LIBUTIL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) + +# Static link! +ADD_DEFINITIONS(-DLIBUTIL_STATIC) + +add_definitions(-DLIBUTIL_LIBRARY) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +IF(MultiMC_CODE_COVERAGE) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 --coverage") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 --coverage") + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 --coverage") + SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O0 --coverage") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0 --coverage") +ENDIF(MultiMC_CODE_COVERAGE) + +add_library(libUtil STATIC ${LIBUTIL_SOURCES}) +# qt5_use_modules(libUtil Core Network) +qt5_use_modules(libUtil Core) +target_link_libraries(libUtil) diff --git a/depends/util/include/cmdutils.h b/depends/util/include/cmdutils.h new file mode 100644 index 00000000..4705f3ca --- /dev/null +++ b/depends/util/include/cmdutils.h @@ -0,0 +1,255 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan <orochimarufan.x3@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <exception> +#include <stdexcept> + +#include <QString> +#include <QVariant> +#include <QHash> +#include <QStringList> + +#include "libutil_config.h" + +/** + * @file libutil/include/cmdutils.h + * @brief commandline parsing and processing utilities + */ + +namespace Util +{ +namespace Commandline +{ + +/** + * @brief split a string into argv items like a shell would do + * @param args the argument string + * @return a QStringList containing all arguments + */ +LIBUTIL_EXPORT QStringList splitArgs(QString args); + +/** + * @brief The FlagStyle enum + * Specifies how flags are decorated + */ + +namespace FlagStyle +{ +enum Enum +{ + GNU, /**< --option and -o (GNU Style) */ + Unix, /**< -option and -o (Unix Style) */ + Windows, /**< /option and /o (Windows Style) */ +#ifdef Q_OS_WIN32 + Default = Windows +#else + Default = GNU +#endif +}; +} + +/** + * @brief The ArgumentStyle enum + */ +namespace ArgumentStyle +{ +enum Enum +{ + Space, /**< --option=value */ + Equals, /**< --option value */ + SpaceAndEquals, /**< --option[= ]value */ +#ifdef Q_OS_WIN32 + Default = Equals +#else + Default = SpaceAndEquals +#endif +}; +} + +/** + * @brief The ParsingError class + */ +class LIBUTIL_EXPORT ParsingError : public std::runtime_error +{ +public: + ParsingError(const QString &what); +}; + +/** + * @brief The Parser class + */ +class LIBUTIL_EXPORT Parser +{ +public: + /** + * @brief Parser constructor + * @param flagStyle the FlagStyle to use in this Parser + * @param argStyle the ArgumentStyle to use in this Parser + */ + Parser(FlagStyle::Enum flagStyle = FlagStyle::Default, + ArgumentStyle::Enum argStyle = ArgumentStyle::Default); + + /** + * @brief set the flag style + * @param style + */ + void setFlagStyle(FlagStyle::Enum style); + + /** + * @brief get the flag style + * @return + */ + FlagStyle::Enum flagStyle(); + + /** + * @brief set the argument style + * @param style + */ + void setArgumentStyle(ArgumentStyle::Enum style); + + /** + * @brief get the argument style + * @return + */ + ArgumentStyle::Enum argumentStyle(); + + /** + * @brief define a boolean switch + * @param name the parameter name + * @param def the default value + */ + void addSwitch(QString name, bool def = false); + + /** + * @brief define an option that takes an additional argument + * @param name the parameter name + * @param def the default value + */ + void addOption(QString name, QVariant def = QVariant()); + + /** + * @brief define a positional argument + * @param name the parameter name + * @param required wether this argument is required + * @param def the default value + */ + void addArgument(QString name, bool required = true, QVariant def = QVariant()); + + /** + * @brief adds a flag to an existing parameter + * @param name the (existing) parameter name + * @param flag the flag character + * @see addSwitch addArgument addOption + * Note: any one parameter can only have one flag + */ + void addShortOpt(QString name, QChar flag); + + /** + * @brief adds documentation to a Parameter + * @param name the parameter name + * @param metavar a string to be displayed as placeholder for the value + * @param doc a QString containing the documentation + * Note: on positional arguments, metavar replaces the name as displayed. + * on options , metavar replaces the value placeholder + */ + void addDocumentation(QString name, QString doc, QString metavar = QString()); + + /** + * @brief generate a help message + * @param progName the program name to use in the help message + * @param helpIndent how much the parameter documentation should be indented + * @param flagsInUsage whether we should use flags instead of options in the usage + * @return a help message + */ + QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true); + + /** + * @brief generate a short usage message + * @param progName the program name to use in the usage message + * @param useFlags whether we should use flags instead of options + * @return a usage message + */ + QString compileUsage(QString progName, bool useFlags = true); + + /** + * @brief parse + * @param argv a QStringList containing the program ARGV + * @return a QHash mapping argument names to their values + */ + QHash<QString, QVariant> parse(QStringList argv); + + /** + * @brief clear all definitions + */ + void clear(); + + ~Parser(); + +private: + FlagStyle::Enum m_flagStyle; + ArgumentStyle::Enum m_argStyle; + + enum OptionType + { + otSwitch, + otOption + }; + + // Important: the common part MUST BE COMMON ON ALL THREE structs + struct CommonDef + { + QString name; + QString doc; + QString metavar; + QVariant def; + }; + + struct OptionDef + { + // common + QString name; + QString doc; + QString metavar; + QVariant def; + // option + OptionType type; + QChar flag; + }; + + struct PositionalDef + { + // common + QString name; + QString doc; + QString metavar; + QVariant def; + // positional + bool required; + }; + + QHash<QString, OptionDef *> m_options; + QHash<QChar, OptionDef *> m_flags; + QHash<QString, CommonDef *> m_params; + QList<PositionalDef *> m_positionals; + QList<OptionDef *> m_optionList; + + void getPrefix(QString &opt, QString &flag); +}; +} +} diff --git a/depends/util/include/libutil_config.h b/depends/util/include/libutil_config.h new file mode 100644 index 00000000..56b33b74 --- /dev/null +++ b/depends/util/include/libutil_config.h @@ -0,0 +1,28 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <QtCore/QtGlobal> + +#ifdef LIBUTIL_STATIC +#define LIBUTIL_EXPORT +#else +#ifdef LIBUTIL_LIBRARY +#define LIBUTIL_EXPORT Q_DECL_EXPORT +#else +#define LIBUTIL_EXPORT Q_DECL_IMPORT +#endif +#endif diff --git a/depends/util/include/osutils.h b/depends/util/include/osutils.h new file mode 100644 index 00000000..d615d31f --- /dev/null +++ b/depends/util/include/osutils.h @@ -0,0 +1,26 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <QString> + +#if defined _WIN32 | defined _WIN64 +#define WINDOWS 1 +#elif __APPLE__ &__MACH__ +#define OSX 1 +#elif __linux__ +#define LINUX 1 +#endif diff --git a/depends/util/include/pathutils.h b/depends/util/include/pathutils.h new file mode 100644 index 00000000..45c2a6de --- /dev/null +++ b/depends/util/include/pathutils.h @@ -0,0 +1,59 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <QString> + +#include "libutil_config.h" + +LIBUTIL_EXPORT QString PathCombine(QString path1, QString path2); +LIBUTIL_EXPORT QString PathCombine(QString path1, QString path2, QString path3); + +LIBUTIL_EXPORT QString AbsolutePath(QString path); + +/** + * Normalize path + * + * Any paths inside the current directory will be normalized to relative paths (to current) + * Other paths will be made absolute + * + * Returns false if the path logic somehow filed (and normalizedPath in invalid) + */ +QString NormalizePath(QString path); + +LIBUTIL_EXPORT QString RemoveInvalidFilenameChars(QString string, QChar replaceWith = '-'); + +LIBUTIL_EXPORT QString DirNameFromString(QString string, QString inDir = "."); + +/** + * Creates all the folders in a path for the specified path + * last segment of the path is treated as a file name and is ignored! + */ +LIBUTIL_EXPORT bool ensureFilePathExists(QString filenamepath); + +/** + * Creates all the folders in a path for the specified path + * last segment of the path is treated as a folder name and is created! + */ +LIBUTIL_EXPORT bool ensureFolderPathExists(QString filenamepath); + +LIBUTIL_EXPORT bool copyPath(QString src, QString dst); + +/// Opens the given file in the default application. +LIBUTIL_EXPORT void openFileInDefaultProgram(QString filename); + +/// Opens the given directory in the default application. +LIBUTIL_EXPORT void openDirInDefaultProgram(QString dirpath, bool ensureExists = false); diff --git a/depends/util/include/userutils.h b/depends/util/include/userutils.h new file mode 100644 index 00000000..6ce08bce --- /dev/null +++ b/depends/util/include/userutils.h @@ -0,0 +1,17 @@ +#pragma once + +#include <QString> + +#include "libutil_config.h" + +namespace Util +{ +// Get the Directory representing the User's Desktop +LIBUTIL_EXPORT QString getDesktopDir(); + +// Create a shortcut at *location*, pointing to *dest* called with the arguments *args* +// call it *name* and assign it the icon *icon* +// return true if operation succeeded +LIBUTIL_EXPORT bool createShortCut(QString location, QString dest, QStringList args, + QString name, QString iconLocation); +} diff --git a/depends/util/src/cmdutils.cpp b/depends/util/src/cmdutils.cpp new file mode 100644 index 00000000..b12098dc --- /dev/null +++ b/depends/util/src/cmdutils.cpp @@ -0,0 +1,486 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan <orochimarufan.x3@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/cmdutils.h" + +/** + * @file libutil/src/cmdutils.cpp + */ + +namespace Util +{ +namespace Commandline +{ + +// commandline splitter +QStringList splitArgs(QString args) +{ + QStringList argv; + QString current; + bool escape = false; + QChar inquotes; + for (int i = 0; i < args.length(); i++) + { + QChar cchar = args.at(i); + + // \ escaped + if (escape) + { + current += cchar; + escape = false; + // in "quotes" + } + else if (!inquotes.isNull()) + { + if (cchar == 0x5C) + escape = true; + else if (cchar == inquotes) + inquotes = 0; + else + current += cchar; + // otherwise + } + else + { + if (cchar == 0x20) + { + if (!current.isEmpty()) + { + argv << current; + current.clear(); + } + } + else if (cchar == 0x22 || cchar == 0x27) + inquotes = cchar; + else + current += cchar; + } + } + if (!current.isEmpty()) + argv << current; + return argv; +} + +Parser::Parser(FlagStyle::Enum flagStyle, ArgumentStyle::Enum argStyle) +{ + m_flagStyle = flagStyle; + m_argStyle = argStyle; +} + +// styles setter/getter +void Parser::setArgumentStyle(ArgumentStyle::Enum style) +{ + m_argStyle = style; +} +ArgumentStyle::Enum Parser::argumentStyle() +{ + return m_argStyle; +} + +void Parser::setFlagStyle(FlagStyle::Enum style) +{ + m_flagStyle = style; +} +FlagStyle::Enum Parser::flagStyle() +{ + return m_flagStyle; +} + +// setup methods +void Parser::addSwitch(QString name, bool def) +{ + if (m_params.contains(name)) + throw "Name not unique"; + + OptionDef *param = new OptionDef; + param->type = otSwitch; + param->name = name; + param->metavar = QString("<%1>").arg(name); + param->def = def; + + m_options[name] = param; + m_params[name] = (CommonDef *)param; + m_optionList.append(param); +} + +void Parser::addOption(QString name, QVariant def) +{ + if (m_params.contains(name)) + throw "Name not unique"; + + OptionDef *param = new OptionDef; + param->type = otOption; + param->name = name; + param->metavar = QString("<%1>").arg(name); + param->def = def; + + m_options[name] = param; + m_params[name] = (CommonDef *)param; + m_optionList.append(param); +} + +void Parser::addArgument(QString name, bool required, QVariant def) +{ + if (m_params.contains(name)) + throw "Name not unique"; + + PositionalDef *param = new PositionalDef; + param->name = name; + param->def = def; + param->required = required; + param->metavar = name; + + m_positionals.append(param); + m_params[name] = (CommonDef *)param; +} + +void Parser::addDocumentation(QString name, QString doc, QString metavar) +{ + if (!m_params.contains(name)) + throw "Name does not exist"; + + CommonDef *param = m_params[name]; + param->doc = doc; + if (!metavar.isNull()) + param->metavar = metavar; +} + +void Parser::addShortOpt(QString name, QChar flag) +{ + if (!m_params.contains(name)) + throw "Name does not exist"; + if (!m_options.contains(name)) + throw "Name is not an Option or Swtich"; + + OptionDef *param = m_options[name]; + m_flags[flag] = param; + param->flag = flag; +} + +// help methods +QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags) +{ + QStringList help; + help << compileUsage(progName, useFlags) << "\r\n"; + + // positionals + if (!m_positionals.isEmpty()) + { + help << "\r\n"; + help << "Positional arguments:\r\n"; + QListIterator<PositionalDef *> it2(m_positionals); + while (it2.hasNext()) + { + PositionalDef *param = it2.next(); + help << " " << param->metavar; + help << " " << QString(helpIndent - param->metavar.length() - 1, ' '); + help << param->doc << "\r\n"; + } + } + + // Options + if (!m_optionList.isEmpty()) + { + help << "\r\n"; + QString optPrefix, flagPrefix; + getPrefix(optPrefix, flagPrefix); + + help << "Options & Switches:\r\n"; + QListIterator<OptionDef *> it(m_optionList); + while (it.hasNext()) + { + OptionDef *option = it.next(); + help << " "; + int nameLength = optPrefix.length() + option->name.length(); + if (!option->flag.isNull()) + { + nameLength += 3 + flagPrefix.length(); + help << flagPrefix << option->flag << ", "; + } + help << optPrefix << option->name; + if (option->type == otOption) + { + QString arg = QString("%1%2").arg( + ((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar); + nameLength += arg.length(); + help << arg; + } + help << " " << QString(helpIndent - nameLength - 1, ' '); + help << option->doc << "\r\n"; + } + } + + return help.join(""); +} + +QString Parser::compileUsage(QString progName, bool useFlags) +{ + QStringList usage; + usage << "Usage: " << progName; + + QString optPrefix, flagPrefix; + getPrefix(optPrefix, flagPrefix); + + // options + QListIterator<OptionDef *> it(m_optionList); + while (it.hasNext()) + { + OptionDef *option = it.next(); + usage << " ["; + if (!option->flag.isNull() && useFlags) + usage << flagPrefix << option->flag; + else + usage << optPrefix << option->name; + if (option->type == otOption) + usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar; + usage << "]"; + } + + // arguments + QListIterator<PositionalDef *> it2(m_positionals); + while (it2.hasNext()) + { + PositionalDef *param = it2.next(); + usage << " " << (param->required ? "<" : "["); + usage << param->metavar; + usage << (param->required ? ">" : "]"); + } + + return usage.join(""); +} + +// parsing +QHash<QString, QVariant> Parser::parse(QStringList argv) +{ + QHash<QString, QVariant> map; + + QStringListIterator it(argv); + QString programName = it.next(); + + QString optionPrefix; + QString flagPrefix; + QListIterator<PositionalDef *> positionals(m_positionals); + QStringList expecting; + + getPrefix(optionPrefix, flagPrefix); + + while (it.hasNext()) + { + QString arg = it.next(); + + if (!expecting.isEmpty()) + // we were expecting an argument + { + QString name = expecting.first(); +/* + if (map.contains(name)) + throw ParsingError( + QString("Option %2%1 was given multiple times").arg(name, optionPrefix)); +*/ + map[name] = QVariant(arg); + + expecting.removeFirst(); + continue; + } + + if (arg.startsWith(optionPrefix)) + // we have an option + { + // qDebug("Found option %s", qPrintable(arg)); + + QString name = arg.mid(optionPrefix.length()); + QString equals; + + if ((m_argStyle == ArgumentStyle::Equals || + m_argStyle == ArgumentStyle::SpaceAndEquals) && + name.contains("=")) + { + int i = name.indexOf("="); + equals = name.mid(i + 1); + name = name.left(i); + } + + if (m_options.contains(name)) + { + /* + if (map.contains(name)) + throw ParsingError(QString("Option %2%1 was given multiple times") + .arg(name, optionPrefix)); +*/ + OptionDef *option = m_options[name]; + if (option->type == otSwitch) + map[name] = true; + else // if (option->type == otOption) + { + if (m_argStyle == ArgumentStyle::Space) + expecting.append(name); + else if (!equals.isNull()) + map[name] = equals; + else if (m_argStyle == ArgumentStyle::SpaceAndEquals) + expecting.append(name); + else + throw ParsingError(QString("Option %2%1 reqires an argument.") + .arg(name, optionPrefix)); + } + + continue; + } + + throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix)); + } + + if (arg.startsWith(flagPrefix)) + // we have (a) flag(s) + { + // qDebug("Found flags %s", qPrintable(arg)); + + QString flags = arg.mid(flagPrefix.length()); + QString equals; + + if ((m_argStyle == ArgumentStyle::Equals || + m_argStyle == ArgumentStyle::SpaceAndEquals) && + flags.contains("=")) + { + int i = flags.indexOf("="); + equals = flags.mid(i + 1); + flags = flags.left(i); + } + + for (int i = 0; i < flags.length(); i++) + { + QChar flag = flags.at(i); + + if (!m_flags.contains(flag)) + throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix)); + + OptionDef *option = m_flags[flag]; +/* + if (map.contains(option->name)) + throw ParsingError(QString("Option %2%1 was given multiple times") + .arg(option->name, optionPrefix)); +*/ + if (option->type == otSwitch) + map[option->name] = true; + else // if (option->type == otOption) + { + if (m_argStyle == ArgumentStyle::Space) + expecting.append(option->name); + else if (!equals.isNull()) + if (i == flags.length() - 1) + map[option->name] = equals; + else + throw ParsingError(QString("Flag %4%2 of Argument-requiring Option " + "%1 not last flag in %4%3") + .arg(option->name, flag, flags, flagPrefix)); + else if (m_argStyle == ArgumentStyle::SpaceAndEquals) + expecting.append(option->name); + else + throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)") + .arg(option->name, flag, flagPrefix)); + } + } + + continue; + } + + // must be a positional argument + if (!positionals.hasNext()) + throw ParsingError(QString("Don't know what to do with '%1'").arg(arg)); + + PositionalDef *param = positionals.next(); + + map[param->name] = arg; + } + + // check if we're missing something + if (!expecting.isEmpty()) + throw ParsingError(QString("Was still expecting arguments for %2%1").arg( + expecting.join(QString(", ") + optionPrefix), optionPrefix)); + + while (positionals.hasNext()) + { + PositionalDef *param = positionals.next(); + if (param->required) + throw ParsingError( + QString("Missing required positional argument '%1'").arg(param->name)); + else + map[param->name] = param->def; + } + + // fill out gaps + QListIterator<OptionDef *> iter(m_optionList); + while (iter.hasNext()) + { + OptionDef *option = iter.next(); + if (!map.contains(option->name)) + map[option->name] = option->def; + } + + return map; +} + +// clear defs +void Parser::clear() +{ + m_flags.clear(); + m_params.clear(); + m_options.clear(); + + QMutableListIterator<OptionDef *> it(m_optionList); + while (it.hasNext()) + { + OptionDef *option = it.next(); + it.remove(); + delete option; + } + + QMutableListIterator<PositionalDef *> it2(m_positionals); + while (it2.hasNext()) + { + PositionalDef *arg = it2.next(); + it2.remove(); + delete arg; + } +} + +// Destructor +Parser::~Parser() +{ + clear(); +} + +// getPrefix +void Parser::getPrefix(QString &opt, QString &flag) +{ + if (m_flagStyle == FlagStyle::Windows) + opt = flag = "/"; + else if (m_flagStyle == FlagStyle::Unix) + opt = flag = "-"; + // else if (m_flagStyle == FlagStyle::GNU) + else + { + opt = "--"; + flag = "-"; + } +} + +// ParsingError +ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString()) +{ +} +} +} diff --git a/depends/util/src/pathutils.cpp b/depends/util/src/pathutils.cpp new file mode 100644 index 00000000..20888754 --- /dev/null +++ b/depends/util/src/pathutils.cpp @@ -0,0 +1,147 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/pathutils.h" + +#include <QFileInfo> +#include <QDir> +#include <QDesktopServices> +#include <QUrl> +#include <QDebug> + +QString PathCombine(QString path1, QString path2) +{ + return QDir::cleanPath(path1 + QDir::separator() + path2); +} + +QString PathCombine(QString path1, QString path2, QString path3) +{ + return PathCombine(PathCombine(path1, path2), path3); +} + +QString AbsolutePath(QString path) +{ + return QFileInfo(path).absolutePath(); +} + +/** + * Normalize path + * + * Any paths inside the current directory will be normalized to relative paths (to current) + * Other paths will be made absolute + */ +QString NormalizePath(QString path) +{ + QDir a = QDir::currentPath(); + QString currentAbsolute = a.absolutePath(); + + QDir b(path); + QString newAbsolute = b.absolutePath(); + + if (newAbsolute.startsWith(currentAbsolute)) + { + return a.relativeFilePath(newAbsolute); + } + else + { + return newAbsolute; + } +} + +QString badFilenameChars = "\"\\/?<>:*|!"; + +QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) +{ + for (int i = 0; i < string.length(); i++) + { + if (badFilenameChars.contains(string[i])) + { + string[i] = replaceWith; + } + } + return string; +} + +QString DirNameFromString(QString string, QString inDir) +{ + int num = 0; + QString dirName = RemoveInvalidFilenameChars(string, '-'); + while (QFileInfo(PathCombine(inDir, dirName)).exists()) + { + num++; + dirName = RemoveInvalidFilenameChars(dirName, '-') + QString::number(num); + + // If it's over 9000 + if (num > 9000) + return ""; + } + return dirName; +} + +bool ensureFilePathExists(QString filenamepath) +{ + QFileInfo a(filenamepath); + QDir dir; + QString ensuredPath = a.path(); + bool success = dir.mkpath(ensuredPath); + return success; +} + +bool ensureFolderPathExists(QString foldernamepath) +{ + QFileInfo a(foldernamepath); + QDir dir; + QString ensuredPath = a.filePath(); + bool success = dir.mkpath(ensuredPath); + return success; +} + +bool copyPath(QString src, QString dst) +{ + QDir dir(src); + if (!dir.exists()) + return false; + if (!ensureFolderPathExists(dst)) + return false; + + foreach(QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) + { + QString inner_src = src + QDir::separator() + d; + QString inner_dst = dst + QDir::separator() + d; + copyPath(inner_src, inner_dst); + } + + foreach(QString f, dir.entryList(QDir::Files)) + { + QFile::copy(src + QDir::separator() + f, dst + QDir::separator() + f); + } + return true; +} + +void openDirInDefaultProgram(QString path, bool ensureExists) +{ + QDir parentPath; + QDir dir(path); + if (!dir.exists()) + { + parentPath.mkpath(dir.absolutePath()); + } + QDesktopServices::openUrl("file:///" + dir.absolutePath()); +} + +void openFileInDefaultProgram(QString filename) +{ + QDesktopServices::openUrl("file:///" + QFileInfo(filename).absolutePath()); +} diff --git a/depends/util/src/userutils.cpp b/depends/util/src/userutils.cpp new file mode 100644 index 00000000..060a58e9 --- /dev/null +++ b/depends/util/src/userutils.cpp @@ -0,0 +1,127 @@ +#include "include/userutils.h" + +#include <QStandardPaths> +#include <QFile> +#include <QTextStream> + +#include "include/osutils.h" +#include "include/pathutils.h" + +// Win32 crap +#if WINDOWS + +#include <windows.h> +#include <winnls.h> +#include <shobjidl.h> +#include <objbase.h> +#include <objidl.h> +#include <shlguid.h> +#include <shlobj.h> + +bool called_coinit = false; + +HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args) +{ + HRESULT hres; + + if (!called_coinit) + { + hres = CoInitialize(NULL); + called_coinit = true; + + if (!SUCCEEDED(hres)) + { + qWarning("Failed to initialize COM. Error 0x%08X", hres); + return hres; + } + } + + IShellLink *link; + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, + (LPVOID *)&link); + + if (SUCCEEDED(hres)) + { + IPersistFile *persistFile; + + link->SetPath(targetPath); + link->SetArguments(args); + + hres = link->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile); + if (SUCCEEDED(hres)) + { + WCHAR wstr[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, linkPath, -1, wstr, MAX_PATH); + + hres = persistFile->Save(wstr, TRUE); + persistFile->Release(); + } + link->Release(); + } + return hres; +} + +#endif + +QString Util::getDesktopDir() +{ + return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); +} + +// Cross-platform Shortcut creation +bool Util::createShortCut(QString location, QString dest, QStringList args, QString name, + QString icon) +{ +#if LINUX + location = PathCombine(location, name + ".desktop"); + qDebug("location: %s", qPrintable(location)); + + QFile f(location); + f.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream stream(&f); + + QString argstring; + if (!args.empty()) + argstring = " '" + args.join("' '") + "'"; + + stream << "[Desktop Entry]" + << "\n"; + stream << "Type=Application" + << "\n"; + stream << "TryExec=" << dest.toLocal8Bit() << "\n"; + stream << "Exec=" << dest.toLocal8Bit() << argstring.toLocal8Bit() << "\n"; + stream << "Name=" << name.toLocal8Bit() << "\n"; + stream << "Icon=" << icon.toLocal8Bit() << "\n"; + + stream.flush(); + f.close(); + + f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | + QFileDevice::ExeOther); + + return true; +#elif WINDOWS + // TODO: Fix + // QFile file(PathCombine(location, name + ".lnk")); + // WCHAR *file_w; + // WCHAR *dest_w; + // WCHAR *args_w; + // file.fileName().toWCharArray(file_w); + // dest.toWCharArray(dest_w); + + // QString argStr; + // for (int i = 0; i < args.count(); i++) + // { + // argStr.append(args[i]); + // argStr.append(" "); + // } + // argStr.toWCharArray(args_w); + + // return SUCCEEDED(CreateLink(file_w, dest_w, args_w)); + return false; +#else + qWarning("Desktop Shortcuts not supported on your platform!"); + return false; +#endif +} |