Clean arguments parsing
This commit is contained in:
parent
5b8b0f8fb8
commit
291c23124f
|
@ -4,22 +4,21 @@ project(sliding-puzzle LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(SOURCES application.cpp board.cpp main.cpp)
|
set(SOURCES application.cpp board.cpp main.cpp argsprocessor.cpp)
|
||||||
set(HEADER_FILES application.h board.h filepath_util.h output_util.h)
|
set(HEADER_FILES application.h board.h filepath_util.h output_util.h argsprocessor.h)
|
||||||
add_executable(sliding-puzzle ${SOURCES} ${HEADER_FILES})
|
|
||||||
|
|
||||||
# STATIC #
|
# STATIC #
|
||||||
# You need to build SFML from sources with cmake
|
# You need to build SFML from sources with cmake
|
||||||
#set(SFML_LIB_DIR
|
set(SFML_LIB_DIR
|
||||||
# ${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-graphics.so.2.5
|
${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-graphics.so.2.5
|
||||||
# ${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-system.so.2.5
|
${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-system.so.2.5
|
||||||
# ${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-window.so.2.5)
|
${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-window.so.2.5)
|
||||||
#set(SFML_INCL_DIR ${CMAKE_SOURCE_DIR}/SFML-2.5.1/include)
|
set(SFML_INCL_DIR ${CMAKE_SOURCE_DIR}/SFML-2.5.1/include)
|
||||||
#include_directories(${SFML_INCL_DIR})
|
include_directories(${SFML_INCL_DIR})
|
||||||
#add_executable(sliding-puzzle ${SOURCES} ${HEADER_FILES} )
|
add_executable(sliding-puzzle ${SOURCES} ${HEADER_FILES} )
|
||||||
#target_link_libraries(sliding-puzzle ${SFML_LIB_DIR})
|
target_link_libraries(sliding-puzzle ${SFML_LIB_DIR})
|
||||||
|
|
||||||
# DYNAMIC #
|
# DYNAMIC #
|
||||||
# You only need to install SFML from your package manager
|
# You only need to install SFML from your package manager
|
||||||
find_package(SFML REQUIRED graphics window system)
|
#find_package(SFML REQUIRED graphics window system)
|
||||||
target_link_libraries(sliding-puzzle sfml-system sfml-graphics sfml-network)
|
#target_link_libraries(sliding-puzzle sfml-system sfml-graphics sfml-network)
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
#include "argsprocessor.h"
|
||||||
|
#include "output_util.h"
|
||||||
|
#include "filepath_util.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static constexpr int DEFAULT_SCREEN_WIDTH = 1280;
|
||||||
|
static constexpr int DEFAULT_SCREEN_HEIGHT = 720;
|
||||||
|
static constexpr int DEFAULT_SPLITTING = 4;
|
||||||
|
static const std::string DEFAULT_PATH = ".";
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ArgsProcessor::ArgsProcessor(int argc, char **argv)
|
||||||
|
{
|
||||||
|
parse_result = tryConvertInput(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArgsProcessor::broken() const
|
||||||
|
{
|
||||||
|
return parse_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<int, sf::Vector2i, std::string> ArgsProcessor::unpack() const
|
||||||
|
{
|
||||||
|
return {image_splitting, game_resolution, image_path};
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArgsProcessor::tryConvertInput(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int error = iterateArgc(argc, argv);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (image_path == DEFAULT_PATH)
|
||||||
|
{
|
||||||
|
// no path was given, loading random image from '.'
|
||||||
|
const auto &[error, ret_path] = filepath::parsePath(image_path);
|
||||||
|
if (error)
|
||||||
|
return makeError(output::IMG_FAIL_MSG);
|
||||||
|
|
||||||
|
image_path = ret_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsProcessor::isFlag(const char *arg, const char *flag) const
|
||||||
|
{
|
||||||
|
return (strcmp(arg, flag) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArgsProcessor::iterateArgc(int argc, char **argv)
|
||||||
|
{
|
||||||
|
for (int current_arg = 1; current_arg < argc; ++current_arg) // current_arg = 0 is executable name
|
||||||
|
{
|
||||||
|
if (isFlag(argv[current_arg], output::HELP_FLAG))
|
||||||
|
return makeError(output::HELP_MSG);
|
||||||
|
|
||||||
|
if (isFlag(argv[current_arg], output::SPLITTING_FLAG))
|
||||||
|
{
|
||||||
|
int error = parseSplitting(current_arg, argc, argv);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
++current_arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFlag(argv[current_arg], output::RESOLUTION_FLAG))
|
||||||
|
{
|
||||||
|
int error = parseResolution(current_arg, argc, argv);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
++current_arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &[error, ret_path] = filepath::parsePath(argv[current_arg]);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return makeError(output::IMG_FAIL_MSG);
|
||||||
|
|
||||||
|
image_path = ret_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArgsProcessor::parseSplitting(int curr_arg, int argc, char **argv)
|
||||||
|
{
|
||||||
|
const int value_rg = curr_arg + 1;
|
||||||
|
if (value_rg == argc)
|
||||||
|
return makeError(output::SPLITTING_MSG);
|
||||||
|
|
||||||
|
image_splitting = -1;
|
||||||
|
if (std::isdigit(*argv[value_rg]))
|
||||||
|
image_splitting = std::stoi(argv[value_rg]);
|
||||||
|
|
||||||
|
if (image_splitting < 2)
|
||||||
|
return makeError(output::SPLITTING_MSG);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArgsProcessor::parseResolution(int curr_arg, int argc, char **argv)
|
||||||
|
{
|
||||||
|
const int value_rg = curr_arg + 1;
|
||||||
|
if (value_rg == argc)
|
||||||
|
return makeError(output::RESOLUTION_MSG);
|
||||||
|
|
||||||
|
std::vector<std::string> res = filepath::split(argv[value_rg], 'x'); // splitting argument by 'x' as in 600x900
|
||||||
|
|
||||||
|
if (res.size() < 2)
|
||||||
|
return makeError(output::RESOLUTION_MSG);
|
||||||
|
|
||||||
|
game_resolution = {-1, -1};
|
||||||
|
|
||||||
|
if (std::isdigit(*res[0].c_str()) && std::isdigit(*res[1].c_str()))
|
||||||
|
game_resolution = {std::stoi(res[0].c_str()), std::stoi(res[1].c_str())};
|
||||||
|
|
||||||
|
if (game_resolution.x < 1 || game_resolution.y < 1)
|
||||||
|
return makeError(output::RESOLUTION_MSG);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArgsProcessor::makeError(const char* msg) const
|
||||||
|
{
|
||||||
|
std::cout << msg;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef ARGSPROCESSOR_H
|
||||||
|
#define ARGSPROCESSOR_H
|
||||||
|
|
||||||
|
#include <SFML/Graphics/VertexArray.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class ArgsProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ArgsProcessor(int argc, char **argv);
|
||||||
|
|
||||||
|
int broken() const;
|
||||||
|
std::tuple<int, sf::Vector2i, std::string> unpack() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isFlag(const char* arg, const char* flag) const;
|
||||||
|
int tryConvertInput(int argc, char **argv);
|
||||||
|
int iterateArgc(int argc, char **argv);
|
||||||
|
int makeError(const char* msg) const;
|
||||||
|
int parseSplitting(int curr_arg, int argc, char **argv);
|
||||||
|
int parseResolution(int curr_arg, int argc, char **argv);
|
||||||
|
|
||||||
|
int parse_result;
|
||||||
|
int image_splitting;
|
||||||
|
sf::Vector2i game_resolution;
|
||||||
|
std::string image_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ARGSPROCESSOR_H
|
106
main.cpp
106
main.cpp
|
@ -1,106 +1,14 @@
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "output_util.h"
|
#include "argsprocessor.h"
|
||||||
#include "filepath_util.h"
|
|
||||||
#include <cstring>
|
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static constexpr int DEFAULT_SCREEN_WIDTH = 1280;
|
|
||||||
static constexpr int DEFAULT_SCREEN_HEIGHT = 720;
|
|
||||||
static constexpr int DEFAULT_SPLITTING = 4;
|
|
||||||
static const std::string DEFAULT_PATH = "."; // current folder, I guess
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
std::tuple<int, int, sf::Vector2i, std::string> error(const char* msg)
|
|
||||||
{
|
|
||||||
std::cout << msg;
|
|
||||||
return {EXIT_FAILURE, -1, {}, {}};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<int, int, sf::Vector2i, std::string> parseInput(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int splitting = DEFAULT_SPLITTING;
|
|
||||||
sf::Vector2i resolution(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT);
|
|
||||||
std::string path = DEFAULT_PATH;
|
|
||||||
|
|
||||||
for (int current_arg = 1; current_arg < argc; ++current_arg) // current_arg = 0 is executable name
|
|
||||||
{
|
|
||||||
if (strcmp(argv[current_arg], output::HELP_FLAG) == 0) // --help
|
|
||||||
return error(output::HELP_MSG);
|
|
||||||
|
|
||||||
if (strcmp(argv[current_arg], output::SPLITTING_FLAG) == 0) // -s num
|
|
||||||
{
|
|
||||||
const int value_rg = current_arg + 1;
|
|
||||||
if (value_rg == argc) // is '-s' is the last argument
|
|
||||||
return error(output::SPLITTING_MSG);
|
|
||||||
|
|
||||||
splitting = -1; // here assuming user is providing it on their own
|
|
||||||
if (std::isdigit(*argv[value_rg]))
|
|
||||||
splitting = std::stoi(argv[value_rg]);
|
|
||||||
|
|
||||||
if (splitting < 2)
|
|
||||||
return error(output::SPLITTING_MSG);
|
|
||||||
|
|
||||||
++current_arg; // skipping value after flag to not check it once again
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(argv[current_arg], output::RESOLUTION_FLAG) == 0) // -r numxnum
|
|
||||||
{
|
|
||||||
const int value_rg = current_arg + 1;
|
|
||||||
if (value_rg == argc) // is '-s' is the last argument
|
|
||||||
return error(output::RESOLUTION_MSG);
|
|
||||||
|
|
||||||
std::vector<std::string> res = filepath::split(argv[value_rg], 'x'); // splitting argument by 'x' as in 600x900
|
|
||||||
|
|
||||||
if (res.size() < 2)
|
|
||||||
return error(output::RESOLUTION_MSG);
|
|
||||||
|
|
||||||
resolution = {-1, -1};
|
|
||||||
|
|
||||||
if (std::isdigit(*res[0].c_str()) && std::isdigit(*res[1].c_str()))
|
|
||||||
resolution = {std::stoi(res[0].c_str()), std::stoi(res[1].c_str())};
|
|
||||||
|
|
||||||
if (resolution.x < 1 || resolution.y < 1)
|
|
||||||
return error(output::RESOLUTION_MSG);
|
|
||||||
|
|
||||||
++current_arg; // skipping value after flag to not check it once again
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// nothing else, then assuming it's filepath or folderpath
|
|
||||||
const auto &[ret_code, ret_path] = filepath::parsePath(argv[current_arg]);
|
|
||||||
|
|
||||||
if (ret_code)
|
|
||||||
return error(output::IMG_FAIL_MSG);
|
|
||||||
|
|
||||||
path = ret_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path == DEFAULT_PATH)
|
|
||||||
{
|
|
||||||
// no path was give, loading random image from '.'
|
|
||||||
const auto &[ret_code, ret_path] = filepath::parsePath(path);
|
|
||||||
|
|
||||||
if (ret_code)
|
|
||||||
return error(output::IMG_FAIL_MSG);
|
|
||||||
|
|
||||||
path = ret_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {EXIT_SUCCESS, splitting, resolution, path};
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const auto&[ret_code, splitting, resolution, path] = parseInput(argc, argv);
|
ArgsProcessor args(argc, argv);
|
||||||
|
|
||||||
if (ret_code)
|
if (args.broken())
|
||||||
return ret_code;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
const auto&[splitting, resolution, path] = args.unpack();
|
||||||
|
|
||||||
Application app(resolution.x, resolution.y);
|
Application app(resolution.x, resolution.y);
|
||||||
if (app.init(path, splitting))
|
if (app.init(path, splitting))
|
||||||
|
@ -108,6 +16,6 @@ int main(int argc, char **argv)
|
||||||
app.run();
|
app.run();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue