Replace getopt/ketopt with parg
This commit is contained in:
parent
0fed381201
commit
456cfb7f0f
@ -45,7 +45,8 @@ set(sources
|
|||||||
db-redis.h
|
db-redis.h
|
||||||
db-sqlite3.cpp
|
db-sqlite3.cpp
|
||||||
db-sqlite3.h
|
db-sqlite3.h
|
||||||
ketopt.h
|
parg.h
|
||||||
|
parg.c
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
@ -64,6 +65,7 @@ if(WIN32)
|
|||||||
include_directories(${SYSTEM_INCLUDE_DIR})
|
include_directories(${SYSTEM_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
set(leveldb_lib "")
|
set(leveldb_lib "")
|
||||||
if(USE_LEVELDB)
|
if(USE_LEVELDB)
|
||||||
set(leveldb_lib ${LEVELDB_LIBRARY})
|
set(leveldb_lib ${LEVELDB_LIBRARY})
|
||||||
@ -88,6 +90,7 @@ if(USE_REDIS)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
#link_directories (../wingetopt)
|
||||||
# Fügen Sie der ausführbaren Datei für dieses Projekt eine Quelle hinzu.
|
# Fügen Sie der ausführbaren Datei für dieses Projekt eine Quelle hinzu.
|
||||||
add_executable (Minetestmapper ${sources})
|
add_executable (Minetestmapper ${sources})
|
||||||
set_target_properties(Minetestmapper PROPERTIES COMPILE_FLAGS -DBUILDER_STATIC_DEFINE)
|
set_target_properties(Minetestmapper PROPERTIES COMPILE_FLAGS -DBUILDER_STATIC_DEFINE)
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "ketopt.h"
|
#include "parg.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -50,80 +50,82 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
auto begin = std::chrono::high_resolution_clock::now();
|
auto begin = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
// TODO: Get rid of getopt and use a proper cmdarg parsing lib or write something own.
|
// TODO: Get rid of getopt and use a proper cmdarg parsing lib or write something own.
|
||||||
static ko_longopt_t long_options[] =
|
static struct parg_option long_options[] =
|
||||||
{
|
{
|
||||||
{ "help", ko_no_argument, 'h' },
|
{ "help", PARG_NOARG, nullptr, 'h' },
|
||||||
{ "version", ko_no_argument, 'V' },
|
{ "version", PARG_NOARG, nullptr, 'V' },
|
||||||
{ "input", ko_required_argument, 'i' },
|
{ "input", PARG_REQARG, nullptr, 'i' },
|
||||||
{ "output", ko_required_argument, 'o' },
|
{ "output", PARG_REQARG, nullptr, 'o' },
|
||||||
{ "colors", ko_required_argument, 'C' },
|
{ "colors", PARG_REQARG, nullptr, 'C' },
|
||||||
{ "heightmap-nodes", ko_required_argument, OPT_HEIGHTMAPNODESFILE },
|
{ "heightmap-nodes", PARG_REQARG, nullptr, OPT_HEIGHTMAPNODESFILE },
|
||||||
{ "heightmap-colors", ko_required_argument, OPT_HEIGHTMAPCOLORSFILE },
|
{ "heightmap-colors", PARG_REQARG, nullptr, OPT_HEIGHTMAPCOLORSFILE },
|
||||||
{ "heightmap", ko_optional_argument, OPT_HEIGHTMAP },
|
{ "heightmap", PARG_OPTARG, nullptr, OPT_HEIGHTMAP },
|
||||||
{ "heightmap-yscale", ko_required_argument, OPT_HEIGHTMAPYSCALE },
|
{ "heightmap-yscale", PARG_REQARG, nullptr, OPT_HEIGHTMAPYSCALE },
|
||||||
{ "height-level-0", ko_required_argument, OPT_HEIGHT_LEVEL0 },
|
{ "height-level-0", PARG_REQARG, nullptr, OPT_HEIGHT_LEVEL0 },
|
||||||
{ "bgcolor", ko_required_argument, 'b' },
|
{ "bgcolor", PARG_REQARG, nullptr, 'b' },
|
||||||
{ "blockcolor", ko_required_argument, OPT_BLOCKCOLOR },
|
{ "blockcolor", PARG_REQARG, nullptr, OPT_BLOCKCOLOR },
|
||||||
{ "scalecolor", ko_required_argument, 's' },
|
{ "scalecolor", PARG_REQARG, nullptr, 's' },
|
||||||
{ "origincolor", ko_required_argument, 'r' },
|
{ "origincolor", PARG_REQARG, nullptr, 'r' },
|
||||||
{ "playercolor", ko_required_argument, 'p' },
|
{ "playercolor", PARG_REQARG, nullptr, 'p' },
|
||||||
{ "draworigin", ko_no_argument, 'R' },
|
{ "draworigin", PARG_NOARG, nullptr, 'R' },
|
||||||
{ "drawplayers", ko_no_argument, 'P' },
|
{ "drawplayers", PARG_NOARG, nullptr, 'P' },
|
||||||
{ "drawscale", ko_optional_argument, 'S' },
|
{ "drawscale", PARG_OPTARG, nullptr, 'S' },
|
||||||
{ "sidescale-interval", ko_required_argument, OPT_SCALEINTERVAL },
|
{ "sidescale-interval", PARG_REQARG, nullptr, OPT_SCALEINTERVAL },
|
||||||
{ "drawheightscale", ko_no_argument, OPT_DRAWHEIGHTSCALE },
|
{ "drawheightscale", PARG_NOARG, nullptr, OPT_DRAWHEIGHTSCALE },
|
||||||
{ "heightscale-interval", ko_required_argument, OPT_SCALEINTERVAL },
|
{ "heightscale-interval", PARG_REQARG, nullptr, OPT_SCALEINTERVAL },
|
||||||
{ "drawalpha", ko_optional_argument, 'e' },
|
{ "drawalpha", PARG_OPTARG, nullptr, 'e' },
|
||||||
{ "drawair", ko_no_argument, OPT_DRAWAIR },
|
{ "drawair", PARG_NOARG, nullptr, OPT_DRAWAIR },
|
||||||
{ "drawnodes", ko_required_argument, OPT_DRAWNODES },
|
{ "drawnodes", PARG_REQARG, nullptr, OPT_DRAWNODES },
|
||||||
{ "ignorenodes", ko_required_argument, OPT_DRAWNODES },
|
{ "ignorenodes", PARG_REQARG, nullptr, OPT_DRAWNODES },
|
||||||
{ "drawpoint", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawpoint", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawline", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawline", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawcircle", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawcircle", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawellipse", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawellipse", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawrectangle", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawrectangle", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawarrow", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawarrow", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawtext", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawtext", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawmappoint", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawmappoint", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawmapline", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawmapline", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawmapcircle", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawmapcircle", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawmapellipse", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawmapellipse", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawmaprectangle", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawmaprectangle", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawmaparrow", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawmaparrow", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "drawmaptext", ko_required_argument, OPT_DRAW_OBJECT },
|
{ "drawmaptext", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||||
{ "noshading", ko_no_argument, 'H' },
|
{ "noshading", PARG_NOARG, nullptr, 'H' },
|
||||||
{ "geometry", ko_required_argument, 'g' },
|
{ "geometry", PARG_REQARG, nullptr, 'g' },
|
||||||
{ "cornergeometry", ko_required_argument, 'g' },
|
{ "cornergeometry", PARG_REQARG, nullptr, 'g' },
|
||||||
{ "centergeometry", ko_required_argument, 'g' },
|
{ "centergeometry", PARG_REQARG, nullptr, 'g' },
|
||||||
{ "geometrymode", ko_required_argument, 'G' },
|
{ "geometrymode", PARG_REQARG, nullptr, 'G' },
|
||||||
{ "forcegeometry", ko_no_argument, 'G' },
|
{ "forcegeometry", PARG_NOARG, nullptr, 'G' },
|
||||||
{ "min-y", ko_required_argument, 'a' },
|
{ "min-y", PARG_REQARG, nullptr, 'a' },
|
||||||
{ "max-y", ko_required_argument, 'c' },
|
{ "max-y", PARG_REQARG, nullptr, 'c' },
|
||||||
{ "backend", ko_required_argument, 'd' },
|
{ "backend", PARG_REQARG, nullptr, 'd' },
|
||||||
{ "disable-blocklist-prefetch", ko_optional_argument, OPT_NO_BLOCKLIST_PREFETCH },
|
{ "disable-blocklist-prefetch", PARG_OPTARG, nullptr, OPT_NO_BLOCKLIST_PREFETCH },
|
||||||
{ "database-format", ko_required_argument, OPT_DATABASE_FORMAT },
|
{ "database-format", PARG_REQARG, nullptr, OPT_DATABASE_FORMAT },
|
||||||
{ "prescan-world", ko_required_argument, OPT_PRESCAN_WORLD },
|
{ "prescan-world", PARG_REQARG, nullptr, OPT_PRESCAN_WORLD },
|
||||||
{ "sqlite-cacheworldrow", ko_no_argument, OPT_SQLITE_CACHEWORLDROW },
|
{ "sqlite-cacheworldrow", PARG_NOARG, nullptr, OPT_SQLITE_CACHEWORLDROW },
|
||||||
{ "sqlite3-limit-prescan-query-size", ko_optional_argument, OPT_SQLITE_LIMIT_PRESCAN_QUERY },
|
{ "sqlite3-limit-prescan-query-size", PARG_OPTARG, nullptr, OPT_SQLITE_LIMIT_PRESCAN_QUERY },
|
||||||
{ "tiles", ko_required_argument, 't' },
|
{ "tiles", PARG_REQARG, nullptr, 't' },
|
||||||
{ "tileorigin", ko_required_argument, 'T' },
|
{ "tileorigin", PARG_REQARG, nullptr, 'T' },
|
||||||
{ "tilecenter", ko_required_argument, 'T' },
|
{ "tilecenter", PARG_REQARG, nullptr, 'T' },
|
||||||
{ "tilebordercolor", ko_required_argument, 'B' },
|
{ "tilebordercolor", PARG_REQARG, nullptr, 'B' },
|
||||||
{ "scalefactor", ko_required_argument, OPT_SCALEFACTOR },
|
{ "scalefactor", PARG_REQARG, nullptr, OPT_SCALEFACTOR },
|
||||||
{ "chunksize", ko_required_argument, OPT_CHUNKSIZE },
|
{ "chunksize", PARG_REQARG, nullptr, OPT_CHUNKSIZE },
|
||||||
{ "silence-suggestions", ko_required_argument, OPT_SILENCE_SUGGESTIONS },
|
{ "silence-suggestions", PARG_REQARG, nullptr, OPT_SILENCE_SUGGESTIONS },
|
||||||
{ "verbose", ko_optional_argument, 'v' },
|
{ "verbose", PARG_OPTARG, nullptr, 'v' },
|
||||||
{ "verbose-search-colors", ko_optional_argument, OPT_VERBOSE_SEARCH_COLORS },
|
{ "verbose-search-colors", PARG_OPTARG, nullptr, OPT_VERBOSE_SEARCH_COLORS },
|
||||||
{ "progress", ko_no_argument, OPT_PROGRESS_INDICATOR },
|
{ "progress", PARG_NOARG, nullptr, OPT_PROGRESS_INDICATOR },
|
||||||
{ nullptr, 0, 0 }
|
{ nullptr, 0, nullptr, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//int option_index = 0;
|
int option_index = 0;
|
||||||
ketopt_t opt = KETOPT_INIT;
|
|
||||||
int c = 0;
|
int c = 0;
|
||||||
|
struct parg_state ps;
|
||||||
|
|
||||||
|
parg_init(&ps);
|
||||||
while (true) {
|
while (true) {
|
||||||
c = ketopt(&opt, argc, argv, 0, "hi:o:", long_options);
|
c = parg_getopt_long(&ps, argc, argv, "hi:o:", long_options, &option_index);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
if (input.empty() || output.empty()) {
|
if (input.empty() || output.empty()) {
|
||||||
std::cerr << "Input (world directory) or output (PNG filename) missing" << std::endl;
|
std::cerr << "Input (world directory) or output (PNG filename) missing" << std::endl;
|
||||||
@ -134,19 +136,21 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '?':
|
case '?':
|
||||||
if (opt.opt == 0) // Unknown long option
|
if (option_index) {
|
||||||
std::cerr << "Unknown Option: '" << argv[opt.ind - 1] << "'." << std::endl;
|
cout << "Comandline Error: Option '--" << long_options[option_index].name << "' does not take an argument: "
|
||||||
else
|
<< argv[ps.optind - 1] << endl;
|
||||||
std::cerr << "Unknown Option: '-" << static_cast<char>(opt.opt) << "'." << std::endl;
|
}
|
||||||
usage();
|
else {
|
||||||
|
cout << "Comandline Error: Unknown option '" << argv[ps.optind - 1]<< "'" << endl;
|
||||||
|
}
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cout << "Comandline Error: Not a option '" << argv[ps.optind - 1] <<"'"<< endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
break;
|
break;
|
||||||
case ':':
|
case ':':
|
||||||
if (opt.longidx != -1)
|
cout << "Comandline Error: Option does not take an argument '" << argv[ps.optind - 1]<< "'" << endl;
|
||||||
std::cerr << "Missing Argument: --'" << long_options[opt.longidx].name << "'." << std::endl;
|
|
||||||
else
|
|
||||||
std::cerr << "Missing Argument: -'" << opt.opt << "'." << std::endl;
|
|
||||||
usage();
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
@ -158,29 +162,29 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
input = opt.arg;
|
input = ps.optarg;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
output = opt.arg;
|
output = ps.optarg;
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
nodeColorsFile = opt.arg;
|
nodeColorsFile = ps.optarg;
|
||||||
break;
|
break;
|
||||||
case OPT_HEIGHTMAPNODESFILE:
|
case OPT_HEIGHTMAPNODESFILE:
|
||||||
heightMapNodesFile = opt.arg;
|
heightMapNodesFile = ps.optarg;
|
||||||
break;
|
break;
|
||||||
case OPT_HEIGHTMAPCOLORSFILE:
|
case OPT_HEIGHTMAPCOLORSFILE:
|
||||||
heightMapColorsFile = opt.arg;
|
heightMapColorsFile = ps.optarg;
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
generator.setBgColor(Color(opt.arg, 0));
|
generator.setBgColor(Color(ps.optarg, 0));
|
||||||
break;
|
break;
|
||||||
case OPT_NO_BLOCKLIST_PREFETCH:
|
case OPT_NO_BLOCKLIST_PREFETCH:
|
||||||
if (opt.arg && *opt.arg) {
|
if (ps.optarg && *ps.optarg) {
|
||||||
if (strlower(opt.arg) == "force")
|
if (strlower(ps.optarg) == "force")
|
||||||
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetchForced);
|
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetchForced);
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name << "'; expected 'force' or nothing." << std::endl;
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "'; expected 'force' or nothing." << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -190,54 +194,54 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_DATABASE_FORMAT: {
|
case OPT_DATABASE_FORMAT: {
|
||||||
std::string option = strlower(opt.arg);
|
std::string opt = strlower(ps.optarg);
|
||||||
if (option == "minetest-i64")
|
if (opt == "minetest-i64")
|
||||||
generator.setDBFormat(BlockPos::I64, false);
|
generator.setDBFormat(BlockPos::I64, false);
|
||||||
else if (option == "freeminer-axyz")
|
else if (opt == "freeminer-axyz")
|
||||||
generator.setDBFormat(BlockPos::AXYZ, false);
|
generator.setDBFormat(BlockPos::AXYZ, false);
|
||||||
else if (option == "mixed")
|
else if (opt == "mixed")
|
||||||
generator.setDBFormat(BlockPos::Unknown, false);
|
generator.setDBFormat(BlockPos::Unknown, false);
|
||||||
else if (option == "query")
|
else if (opt == "query")
|
||||||
generator.setDBFormat(BlockPos::Unknown, true);
|
generator.setDBFormat(BlockPos::Unknown, true);
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name << "': '" << opt.arg << "'" << std::endl;
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_PRESCAN_WORLD: {
|
case OPT_PRESCAN_WORLD: {
|
||||||
std::string option = strlower(opt.arg);
|
std::string opt = strlower(ps.optarg);
|
||||||
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::Prefetch);
|
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::Prefetch);
|
||||||
if (option == "disabled-force")
|
if (opt == "disabled-force")
|
||||||
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetchForced);
|
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetchForced);
|
||||||
else if (option == "disabled")
|
else if (opt == "disabled")
|
||||||
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetch);
|
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetch);
|
||||||
else if (option == "auto")
|
else if (opt == "auto")
|
||||||
generator.setScanEntireWorld(false);
|
generator.setScanEntireWorld(false);
|
||||||
else if (option == "full")
|
else if (opt == "full")
|
||||||
generator.setScanEntireWorld(true);
|
generator.setScanEntireWorld(true);
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name << "': '" << opt.arg << "'" << std::endl;
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_SQLITE_LIMIT_PRESCAN_QUERY:
|
case OPT_SQLITE_LIMIT_PRESCAN_QUERY:
|
||||||
if (!opt.arg || !*opt.arg) {
|
if (!ps.optarg || !*ps.optarg) {
|
||||||
#ifdef USE_SQLITE3
|
#ifdef USE_SQLITE3
|
||||||
DBSQLite3::setLimitBlockListQuerySize();
|
DBSQLite3::setLimitBlockListQuerySize();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!isdigit(opt.arg[0])) {
|
if (!isdigit(ps.optarg[0])) {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name << "': must be a positive number" << std::endl;
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': must be a positive number" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
#ifdef USE_SQLITE3
|
#ifdef USE_SQLITE3
|
||||||
int size = atoi(opt.arg);
|
int size = atoi(ps.optarg);
|
||||||
DBSQLite3::setLimitBlockListQuerySize(size);
|
DBSQLite3::setLimitBlockListQuerySize(size);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -245,9 +249,9 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
case OPT_HEIGHTMAP:
|
case OPT_HEIGHTMAP:
|
||||||
generator.setHeightMap(true);
|
generator.setHeightMap(true);
|
||||||
heightMap = true;
|
heightMap = true;
|
||||||
if (opt.arg && *opt.arg) {
|
if (ps.optarg && *ps.optarg) {
|
||||||
loadHeightMapColorsFile = false;
|
loadHeightMapColorsFile = false;
|
||||||
std::string color = strlower(opt.arg);
|
std::string color = strlower(ps.optarg);
|
||||||
if (color == "grey" || color == "gray")
|
if (color == "grey" || color == "gray")
|
||||||
generator.setHeightMapColor(Color(0, 0, 0), Color(255, 255, 255));
|
generator.setHeightMapColor(Color(0, 0, 0), Color(255, 255, 255));
|
||||||
else if (color == "black")
|
else if (color == "black")
|
||||||
@ -263,41 +267,41 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_HEIGHTMAPYSCALE:
|
case OPT_HEIGHTMAPYSCALE:
|
||||||
if (isdigit(opt.arg[0]) || ((opt.arg[0] == '-' || opt.arg[0] == '+') && isdigit(opt.arg[1]))) {
|
if (isdigit(ps.optarg[0]) || ((ps.optarg[0] == '-' || ps.optarg[0] == '+') && isdigit(ps.optarg[1]))) {
|
||||||
float scale = static_cast<float>(atof(opt.arg));
|
float scale = static_cast<float>(atof(ps.optarg));
|
||||||
generator.setHeightMapYScale(scale);
|
generator.setHeightMapYScale(scale);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name << "': '" << opt.arg << "'" << std::endl;
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_HEIGHT_LEVEL0:
|
case OPT_HEIGHT_LEVEL0:
|
||||||
if (isdigit(opt.arg[0]) || ((opt.arg[0] == '-' || opt.arg[0] == '+') && isdigit(opt.arg[1]))) {
|
if (isdigit(ps.optarg[0]) || ((ps.optarg[0] == '-' || ps.optarg[0] == '+') && isdigit(ps.optarg[1]))) {
|
||||||
int level = atoi(opt.arg);
|
int level = atoi(ps.optarg);
|
||||||
generator.setSeaLevel(level);
|
generator.setSeaLevel(level);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name << "': '" << opt.arg << "'" << std::endl;
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_BLOCKCOLOR:
|
case OPT_BLOCKCOLOR:
|
||||||
generator.setBlockDefaultColor(Color(opt.arg, 0));
|
generator.setBlockDefaultColor(Color(ps.optarg, 0));
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
generator.setScaleColor(Color(opt.arg, 0));
|
generator.setScaleColor(Color(ps.optarg, 0));
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
generator.setOriginColor(Color(opt.arg, 1));
|
generator.setOriginColor(Color(ps.optarg, 1));
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
generator.setPlayerColor(Color(opt.arg, 1));
|
generator.setPlayerColor(Color(ps.optarg, 1));
|
||||||
break;
|
break;
|
||||||
case 'B':
|
case 'B':
|
||||||
generator.setTileBorderColor(Color(opt.arg, 0));
|
generator.setTileBorderColor(Color(ps.optarg, 0));
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
generator.setDrawOrigin(true);
|
generator.setDrawOrigin(true);
|
||||||
@ -306,19 +310,19 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
generator.setDrawPlayers(true);
|
generator.setDrawPlayers(true);
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
if (opt.arg && *opt.arg) {
|
if (ps.optarg && *ps.optarg) {
|
||||||
std::string option = strlower(opt.arg);
|
std::string opt = strlower(ps.optarg);
|
||||||
if (option == "left")
|
if (opt == "left")
|
||||||
generator.setDrawScale(DRAWSCALE_LEFT);
|
generator.setDrawScale(DRAWSCALE_LEFT);
|
||||||
else if (option == "top")
|
else if (opt == "top")
|
||||||
generator.setDrawScale(DRAWSCALE_TOP);
|
generator.setDrawScale(DRAWSCALE_TOP);
|
||||||
else if (option == "left,top")
|
else if (opt == "left,top")
|
||||||
generator.setDrawScale(DRAWSCALE_LEFT | DRAWSCALE_TOP);
|
generator.setDrawScale(DRAWSCALE_LEFT | DRAWSCALE_TOP);
|
||||||
else if (option == "top,left")
|
else if (opt == "top,left")
|
||||||
generator.setDrawScale(DRAWSCALE_LEFT | DRAWSCALE_TOP);
|
generator.setDrawScale(DRAWSCALE_LEFT | DRAWSCALE_TOP);
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name
|
||||||
<< "': '" << opt.arg << "' (expected: left,top)" << std::endl;
|
<< "': '" << ps.optarg << "' (expected: left,top)" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -332,29 +336,29 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case OPT_SCALEINTERVAL: {
|
case OPT_SCALEINTERVAL: {
|
||||||
istringstream arg;
|
istringstream arg;
|
||||||
arg.str(opt.arg);
|
arg.str(ps.optarg);
|
||||||
int major;
|
int major;
|
||||||
int minor;
|
int minor;
|
||||||
char sep;
|
char sep;
|
||||||
arg >> major;
|
arg >> major;
|
||||||
if (major < 0 || !isdigit(*opt.arg) || arg.fail()) {
|
if (major < 0 || !isdigit(*ps.optarg) || arg.fail()) {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name
|
||||||
<< "': '" << opt.arg << "' (expected: <major>[,<minor>]" << std::endl;
|
<< "': '" << ps.optarg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
arg >> std::ws >> sep >> std::ws;
|
arg >> std::ws >> sep >> std::ws;
|
||||||
if (!arg.fail()) {
|
if (!arg.fail()) {
|
||||||
if ((sep != ',' && sep != ':') || !isdigit(arg.peek())) {
|
if ((sep != ',' && sep != ':') || !isdigit(arg.peek())) {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name
|
||||||
<< "': '" << opt.arg << "' (expected: <major>[,<minor>]" << std::endl;
|
<< "': '" << ps.optarg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
arg >> minor;
|
arg >> minor;
|
||||||
if (minor < 0) {
|
if (minor < 0) {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name
|
||||||
<< "': '" << opt.arg << "' (expected: <major>[,<minor>]" << std::endl;
|
<< "': '" << ps.optarg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -364,7 +368,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
if (minor && sep == ':') {
|
if (minor && sep == ':') {
|
||||||
if (major % minor) {
|
if (major % minor) {
|
||||||
std::cerr << long_options[opt.ind].name << ": Cannot divide major interval in "
|
std::cerr << long_options[option_index].name << ": Cannot divide major interval in "
|
||||||
<< minor << " subintervals (not divisible)" << std::endl;
|
<< minor << " subintervals (not divisible)" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -372,25 +376,25 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
if ((minor % major) == 0)
|
if ((minor % major) == 0)
|
||||||
minor = 0;
|
minor = 0;
|
||||||
if (long_options[opt.ind].name[0] == 's') {
|
if (long_options[option_index].name[0] == 's') {
|
||||||
generator.setSideScaleInterval(major, minor);
|
generator.setSideScaleInterval(major, minor);
|
||||||
}
|
}
|
||||||
else if (long_options[opt.ind].name[0] == 'h') {
|
else if (long_options[option_index].name[0] == 'h') {
|
||||||
generator.setHeightScaleInterval(major, minor);
|
generator.setHeightScaleInterval(major, minor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cerr << "Internal error: option " << long_options[opt.ind].name << " not handled" << std::endl;
|
std::cerr << "Internal error: option " << long_options[option_index].name << " not handled" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_SILENCE_SUGGESTIONS: {
|
case OPT_SILENCE_SUGGESTIONS: {
|
||||||
for (size_t i = 0; i < strlen(opt.arg); i++) {
|
string optarg = strlower(ps.optarg);
|
||||||
opt.arg[i] = tolower(opt.arg[i]);
|
for(char &c : optarg) {
|
||||||
if (opt.arg[i] == ',')
|
if (c == ',')
|
||||||
opt.arg[i] = ' ';
|
c = ' ';
|
||||||
}
|
}
|
||||||
std::istringstream iss(opt.arg);
|
std::istringstream iss(optarg);
|
||||||
std::string flag;
|
std::string flag;
|
||||||
iss >> std::skipws >> flag;
|
iss >> std::skipws >> flag;
|
||||||
while (!iss.fail()) {
|
while (!iss.fail()) {
|
||||||
@ -407,7 +411,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid flag to '" << long_options[opt.ind].name << "': '" << flag << "'" << std::endl;
|
std::cerr << "Invalid flag to '" << long_options[option_index].name << "': '" << flag << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -416,9 +420,9 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
if (opt.arg && isdigit(opt.arg[0]) && opt.arg[1] == '\0') {
|
if (ps.optarg && isdigit(ps.optarg[0]) && ps.optarg[1] == '\0') {
|
||||||
generator.verboseStatistics = opt.arg[0] - '0';
|
generator.verboseStatistics = ps.optarg[0] - '0';
|
||||||
generator.verboseCoordinates = opt.arg[0] - '0';
|
generator.verboseCoordinates = ps.optarg[0] - '0';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generator.verboseStatistics = 1;
|
generator.verboseStatistics = 1;
|
||||||
@ -426,29 +430,30 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_VERBOSE_SEARCH_COLORS:
|
case OPT_VERBOSE_SEARCH_COLORS:
|
||||||
if (opt.arg && isdigit(opt.arg[0]) && opt.arg[1] == '\0') {
|
if (ps.optarg && isdigit(ps.optarg[0]) && ps.optarg[1] == '\0') {
|
||||||
generator.verboseReadColors = opt.arg[0] - '0';
|
generator.verboseReadColors = ps.optarg[0] - '0';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generator.verboseReadColors++;
|
generator.verboseReadColors++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
|
// Todo: Unnecessary calls to strlower. Optimize
|
||||||
generator.setDrawAlpha(true);
|
generator.setDrawAlpha(true);
|
||||||
if (!opt.arg || !*opt.arg)
|
if (!ps.optarg || !*ps.optarg)
|
||||||
PixelAttribute::setMixMode(PixelAttribute::AlphaMixAverage);
|
PixelAttribute::setMixMode(PixelAttribute::AlphaMixAverage);
|
||||||
else if (string(opt.arg) == "cumulative" || strlower(opt.arg) == "nodarken")
|
else if (string(ps.optarg) == "cumulative" || strlower(ps.optarg) == "nodarken")
|
||||||
// "nodarken" is supported for backwards compatibility
|
// "nodarken" is supported for backwards compatibility
|
||||||
PixelAttribute::setMixMode(PixelAttribute::AlphaMixCumulative);
|
PixelAttribute::setMixMode(PixelAttribute::AlphaMixCumulative);
|
||||||
else if (string(opt.arg) == "darken" || strlower(opt.arg) == "cumulative-darken")
|
else if (string(ps.optarg) == "darken" || strlower(ps.optarg) == "cumulative-darken")
|
||||||
// "darken" is supported for backwards compatibility
|
// "darken" is supported for backwards compatibility
|
||||||
PixelAttribute::setMixMode(PixelAttribute::AlphaMixCumulativeDarken);
|
PixelAttribute::setMixMode(PixelAttribute::AlphaMixCumulativeDarken);
|
||||||
else if (strlower(opt.arg) == "average")
|
else if (strlower(ps.optarg) == "average")
|
||||||
PixelAttribute::setMixMode(PixelAttribute::AlphaMixAverage);
|
PixelAttribute::setMixMode(PixelAttribute::AlphaMixAverage);
|
||||||
else if (strlower(opt.arg) == "none")
|
else if (strlower(ps.optarg) == "none")
|
||||||
generator.setDrawAlpha(false);
|
generator.setDrawAlpha(false);
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name << "': '" << opt.arg << "'" << std::endl;
|
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -457,12 +462,12 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
generator.setDrawAir(true);
|
generator.setDrawAir(true);
|
||||||
break;
|
break;
|
||||||
case OPT_DRAWNODES: {
|
case OPT_DRAWNODES: {
|
||||||
bool draw = long_options[opt.ind].name[0] == 'd';
|
bool draw = long_options[option_index].name[0] == 'd';
|
||||||
for (char *c = opt.arg; *c; c++) {
|
string optarg = strlower(ps.optarg);
|
||||||
*c = tolower(*c);
|
for (char &c : optarg){
|
||||||
if (*c == ',') *c = ' ';
|
if (c == ',') c = ' ';
|
||||||
}
|
}
|
||||||
istringstream iss(opt.arg);
|
istringstream iss(optarg);
|
||||||
string flag;
|
string flag;
|
||||||
iss >> std::skipws >> flag;
|
iss >> std::skipws >> flag;
|
||||||
while (!iss.fail()) {
|
while (!iss.fail()) {
|
||||||
@ -478,7 +483,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
else if (flag == "air")
|
else if (flag == "air")
|
||||||
generator.setDrawAir(enable);
|
generator.setDrawAir(enable);
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid " << long_options[opt.ind].name << " flag '" << flag << "'" << std::endl;
|
std::cerr << "Invalid " << long_options[option_index].name << " flag '" << flag << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -501,7 +506,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case 'a': {
|
case 'a': {
|
||||||
istringstream iss;
|
istringstream iss;
|
||||||
iss.str(opt.arg);
|
iss.str(ps.optarg);
|
||||||
int miny;
|
int miny;
|
||||||
iss >> miny;
|
iss >> miny;
|
||||||
generator.setMinY(miny);
|
generator.setMinY(miny);
|
||||||
@ -509,7 +514,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case 'c': {
|
case 'c': {
|
||||||
istringstream iss;
|
istringstream iss;
|
||||||
iss.str(opt.arg);
|
iss.str(ps.optarg);
|
||||||
int maxy;
|
int maxy;
|
||||||
iss >> maxy;
|
iss >> maxy;
|
||||||
generator.setMaxY(maxy);
|
generator.setMaxY(maxy);
|
||||||
@ -517,11 +522,11 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case OPT_CHUNKSIZE: {
|
case OPT_CHUNKSIZE: {
|
||||||
istringstream iss;
|
istringstream iss;
|
||||||
iss.str(opt.arg);
|
iss.str(ps.optarg);
|
||||||
int size;
|
int size;
|
||||||
iss >> size;
|
iss >> size;
|
||||||
if (iss.fail() || size < 0) {
|
if (iss.fail() || size < 0) {
|
||||||
std::cerr << "Invalid chunk size (" << opt.arg << ")" << std::endl;
|
std::cerr << "Invalid chunk size (" << ps.optarg << ")" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -530,19 +535,19 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case OPT_SCALEFACTOR: {
|
case OPT_SCALEFACTOR: {
|
||||||
istringstream arg;
|
istringstream arg;
|
||||||
arg.str(opt.arg);
|
arg.str(ps.optarg);
|
||||||
int one;
|
int one;
|
||||||
char colon;
|
char colon;
|
||||||
int factor = 1;
|
int factor = 1;
|
||||||
arg >> one >> std::ws;
|
arg >> one >> std::ws;
|
||||||
if (arg.fail() || one != 1) {
|
if (arg.fail() || one != 1) {
|
||||||
std::cerr << "Invalid scale factor specification (" << opt.arg << ") - expected: 1:<n>" << std::endl;
|
std::cerr << "Invalid scale factor specification (" << ps.optarg << ") - expected: 1:<n>" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (!arg.eof()) {
|
if (!arg.eof()) {
|
||||||
arg >> colon >> factor >> std::ws;
|
arg >> colon >> factor >> std::ws;
|
||||||
if (arg.fail() || colon != ':' || factor<0 || !arg.eof()) {
|
if (arg.fail() || colon != ':' || factor<0 || !arg.eof()) {
|
||||||
std::cerr << "Invalid scale factor specification (" << opt.arg << ") - expected: 1:<n>" << std::endl;
|
std::cerr << "Invalid scale factor specification (" << ps.optarg << ") - expected: 1:<n>" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -556,7 +561,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case 't': {
|
case 't': {
|
||||||
istringstream tilesize;
|
istringstream tilesize;
|
||||||
tilesize.str(strlower(opt.arg));
|
tilesize.str(strlower(ps.optarg));
|
||||||
if (tilesize.str() == "block") {
|
if (tilesize.str() == "block") {
|
||||||
generator.setTileSize(BLOCK_SIZE, BLOCK_SIZE);
|
generator.setTileSize(BLOCK_SIZE, BLOCK_SIZE);
|
||||||
generator.setTileOrigin(TILECORNER_AT_WORLDCENTER, TILECORNER_AT_WORLDCENTER);
|
generator.setTileOrigin(TILECORNER_AT_WORLDCENTER, TILECORNER_AT_WORLDCENTER);
|
||||||
@ -570,7 +575,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
char c;
|
char c;
|
||||||
tilesize >> size;
|
tilesize >> size;
|
||||||
if (tilesize.fail() || size<0) {
|
if (tilesize.fail() || size<0) {
|
||||||
std::cerr << "Invalid tile size specification (" << opt.arg << ")" << std::endl;
|
std::cerr << "Invalid tile size specification (" << ps.optarg << ")" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -578,7 +583,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
tilesize >> c >> border;
|
tilesize >> c >> border;
|
||||||
if (!tilesize.fail()) {
|
if (!tilesize.fail()) {
|
||||||
if (c != '+' || border < 1) {
|
if (c != '+' || border < 1) {
|
||||||
std::cerr << "Invalid tile border size specification (" << opt.arg << ")" << std::endl;
|
std::cerr << "Invalid tile border size specification (" << ps.optarg << ")" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -588,9 +593,9 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'T': {
|
case 'T': {
|
||||||
bool origin = long_options[opt.ind].name[4] == 'o';
|
bool origin = long_options[option_index].name[4] == 'o';
|
||||||
istringstream iss;
|
istringstream iss;
|
||||||
iss.str(strlower(opt.arg));
|
iss.str(strlower(ps.optarg));
|
||||||
NodeCoord coord;
|
NodeCoord coord;
|
||||||
if (iss.str() == "world") {
|
if (iss.str() == "world") {
|
||||||
if (origin)
|
if (origin)
|
||||||
@ -607,7 +612,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
else {
|
else {
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (!parseCoordinates(iss, coord, 2, 0, ',')) {
|
if (!parseCoordinates(iss, coord, 2, 0, ',')) {
|
||||||
iss.str(opt.arg);
|
iss.str(ps.optarg);
|
||||||
result = parseCoordinates(iss, coord, 2, 0, ':');
|
result = parseCoordinates(iss, coord, 2, 0, ':');
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
@ -621,7 +626,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cerr << "Invalid " << long_options[opt.ind].name << " parameter (" << opt.arg << ")" << std::endl;
|
std::cerr << "Invalid " << long_options[option_index].name << " parameter (" << ps.optarg << ")" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -629,7 +634,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'G':
|
case 'G':
|
||||||
if (long_options[opt.ind].name[0] == 'f') {
|
if (long_options[option_index].name[0] == 'f') {
|
||||||
// '--forcegeometry'
|
// '--forcegeometry'
|
||||||
// Old behavior - for compatibility.
|
// Old behavior - for compatibility.
|
||||||
generator.setShrinkGeometry(false);
|
generator.setShrinkGeometry(false);
|
||||||
@ -637,13 +642,14 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
if (!foundGeometrySpec)
|
if (!foundGeometrySpec)
|
||||||
generator.setBlockGeometry(true);
|
generator.setBlockGeometry(true);
|
||||||
}
|
}
|
||||||
else if (opt.arg && *opt.arg) {
|
else if (ps.optarg && *ps.optarg) {
|
||||||
for (char *c = opt.arg; *c; c++) {
|
string optarg = strlower(ps.optarg);
|
||||||
*c = tolower(*c);
|
for (char &c : optarg) {
|
||||||
if (*c == ',') *c = ' ';
|
if (c == ',')
|
||||||
|
c = ' ';
|
||||||
}
|
}
|
||||||
istringstream iss;
|
istringstream iss;
|
||||||
iss.str(opt.arg);
|
iss.str(optarg);
|
||||||
string flag;
|
string flag;
|
||||||
iss >> std::skipws >> flag;
|
iss >> std::skipws >> flag;
|
||||||
while (!iss.fail()) {
|
while (!iss.fail()) {
|
||||||
@ -671,23 +677,23 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case 'g': {
|
case 'g': {
|
||||||
istringstream iss;
|
istringstream iss;
|
||||||
iss.str(opt.arg);
|
iss.str(ps.optarg);
|
||||||
NodeCoord coord1;
|
NodeCoord coord1;
|
||||||
NodeCoord coord2;
|
NodeCoord coord2;
|
||||||
bool legacy;
|
bool legacy;
|
||||||
FuzzyBool center = FuzzyBool::Maybe;
|
FuzzyBool center = FuzzyBool::Maybe;
|
||||||
if (long_options[opt.ind].name[0] == 'c' && long_options[opt.ind].name[1] == 'e')
|
if (long_options[option_index].name[0] == 'c' && long_options[option_index].name[1] == 'e')
|
||||||
center = FuzzyBool::Yes;
|
center = FuzzyBool::Yes;
|
||||||
if (long_options[opt.ind].name[0] == 'c' && long_options[opt.ind].name[1] == 'o')
|
if (long_options[option_index].name[0] == 'c' && long_options[option_index].name[1] == 'o')
|
||||||
center = FuzzyBool::No;
|
center = FuzzyBool::No;
|
||||||
if (!parseMapGeometry(iss, coord1, coord2, legacy, center)) {
|
if (!parseMapGeometry(iss, coord1, coord2, legacy, center)) {
|
||||||
std::cerr << "Invalid geometry specification '" << opt.arg << "'" << std::endl;
|
std::cerr << "Invalid geometry specification '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
// Set defaults
|
// Set defaults
|
||||||
if (!foundGeometrySpec) {
|
if (!foundGeometrySpec) {
|
||||||
if (long_options[opt.ind].name[0] == 'g' && legacy) {
|
if (long_options[option_index].name[0] == 'g' && legacy) {
|
||||||
// Compatibility when using the option 'geometry'
|
// Compatibility when using the option 'geometry'
|
||||||
generator.setBlockGeometry(true);
|
generator.setBlockGeometry(true);
|
||||||
generator.setShrinkGeometry(true);
|
generator.setShrinkGeometry(true);
|
||||||
@ -711,8 +717,8 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case OPT_DRAW_OBJECT: {
|
case OPT_DRAW_OBJECT: {
|
||||||
TileGenerator::DrawObject drawObject;
|
TileGenerator::DrawObject drawObject;
|
||||||
drawObject.world = long_options[opt.ind].name[4] != 'm';
|
drawObject.world = long_options[option_index].name[4] != 'm';
|
||||||
char object = long_options[opt.ind].name[4 + (drawObject.world ? 0 : 3)];
|
char object = long_options[option_index].name[4 + (drawObject.world ? 0 : 3)];
|
||||||
switch (object) {
|
switch (object) {
|
||||||
case 'p':
|
case 'p':
|
||||||
drawObject.type = TileGenerator::DrawObject::Point;
|
drawObject.type = TileGenerator::DrawObject::Point;
|
||||||
@ -735,14 +741,14 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
std::cerr << "Internal error: unrecognised object ("
|
std::cerr << "Internal error: unrecognised object ("
|
||||||
<< long_options[opt.ind].name
|
<< long_options[option_index].name
|
||||||
<< ")" << std::endl;
|
<< ")" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
istringstream iss;
|
istringstream iss;
|
||||||
iss.str(opt.arg);
|
iss.str(ps.optarg);
|
||||||
NodeCoord coord1;
|
NodeCoord coord1;
|
||||||
NodeCoord coord2;
|
NodeCoord coord2;
|
||||||
NodeCoord dimensions;
|
NodeCoord dimensions;
|
||||||
@ -756,8 +762,8 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
needDimensions = FuzzyBool::Yes;
|
needDimensions = FuzzyBool::Yes;
|
||||||
if (!parseGeometry(iss, coord1, coord2, dimensions, legacy, centered, 2, needDimensions)) {
|
if (!parseGeometry(iss, coord1, coord2, dimensions, legacy, centered, 2, needDimensions)) {
|
||||||
std::cerr << "Invalid drawing geometry specification for "
|
std::cerr << "Invalid drawing geometry specification for "
|
||||||
<< long_options[opt.ind].name
|
<< long_options[option_index].name
|
||||||
<< " '" << opt.arg << "'" << std::endl;
|
<< " '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -800,8 +806,8 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
iss >> std::ws >> colorStr;
|
iss >> std::ws >> colorStr;
|
||||||
if (iss.fail()) {
|
if (iss.fail()) {
|
||||||
std::cerr << "Missing color for "
|
std::cerr << "Missing color for "
|
||||||
<< long_options[opt.ind].name
|
<< long_options[option_index].name
|
||||||
<< " '" << opt.arg << "'" << std::endl;
|
<< " '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -813,8 +819,8 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
std::getline(iss, localizedText);
|
std::getline(iss, localizedText);
|
||||||
if (localizedText.empty() || iss.fail()) {
|
if (localizedText.empty() || iss.fail()) {
|
||||||
std::cerr << "Invalid or missing text for "
|
std::cerr << "Invalid or missing text for "
|
||||||
<< long_options[opt.ind].name
|
<< long_options[option_index].name
|
||||||
<< " '" << opt.arg << "'" << std::endl;
|
<< " '" << ps.optarg << "'" << std::endl;
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -850,9 +856,11 @@ int Mapper::start(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
generator.setBackend(strlower(opt.arg));
|
generator.setBackend(strlower(ps.optarg));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
cout << "Internal Error: Comandline option not handled." << endl
|
||||||
|
<< "Please file a bug to https://github.com/adrido/minetest-mapper-cpp/" << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
|
||||||
This File was taken from https://github.com/attractivechaos/klib/blob/master/ketopt.h and is licensed under MIT license.
|
|
||||||
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h> /* for strchr() and strncmp() */
|
|
||||||
|
|
||||||
#define ko_no_argument 0
|
|
||||||
#define ko_required_argument 1
|
|
||||||
#define ko_optional_argument 2
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int ind; /* equivalent to optind */
|
|
||||||
int opt; /* equivalent to optopt */
|
|
||||||
char *arg; /* equivalent to optarg */
|
|
||||||
int longidx; /* index of a long option; or -1 if short */
|
|
||||||
/* private variables not intended for external uses */
|
|
||||||
int i, pos, n_args;
|
|
||||||
} ketopt_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char *name;
|
|
||||||
int has_arg;
|
|
||||||
int val;
|
|
||||||
} ko_longopt_t;
|
|
||||||
|
|
||||||
static ketopt_t KETOPT_INIT = { 1, 0, 0, -1, 1, 0, 0 };
|
|
||||||
|
|
||||||
static void ketopt_permute(char *argv[], int j, int n) /* move argv[j] over n elements to the left */
|
|
||||||
{
|
|
||||||
int k;
|
|
||||||
char *p = argv[j];
|
|
||||||
for (k = 0; k < n; ++k)
|
|
||||||
argv[j - k] = argv[j - k - 1];
|
|
||||||
argv[j - k] = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse command-line options and arguments
|
|
||||||
*
|
|
||||||
* This fuction has a similar interface to GNU's getopt_long(). Each call
|
|
||||||
* parses one option and returns the option name. s->arg points to the option
|
|
||||||
* argument if present. The function returns -1 when all command-line arguments
|
|
||||||
* are parsed. In this case, s->ind is the index of the first non-option
|
|
||||||
* argument.
|
|
||||||
*
|
|
||||||
* @param s status; shall be initialized to KETOPT_INIT on the first call
|
|
||||||
* @param argc length of argv[]
|
|
||||||
* @param argv list of command-line arguments; argv[0] is ignored
|
|
||||||
* @param permute non-zero to move options ahead of non-option arguments
|
|
||||||
* @param ostr option string
|
|
||||||
* @param longopts long options
|
|
||||||
*
|
|
||||||
* @return ASCII for a short option; ko_longopt_t::val for a long option; -1 if
|
|
||||||
* argv[] is fully processed; '?' for an unknown option or an ambiguous
|
|
||||||
* long option; ':' if an option argument is missing
|
|
||||||
*/
|
|
||||||
static int ketopt(ketopt_t *s, int argc, char *argv[], int permute, const char *ostr, const ko_longopt_t *longopts)
|
|
||||||
{
|
|
||||||
int opt = -1, i0, j;
|
|
||||||
if (permute) {
|
|
||||||
while (s->i < argc && (argv[s->i][0] != '-' || argv[s->i][1] == '\0'))
|
|
||||||
++s->i, ++s->n_args;
|
|
||||||
}
|
|
||||||
s->arg = 0, s->longidx = -1, i0 = s->i;
|
|
||||||
if (s->i >= argc || argv[s->i][0] != '-' || argv[s->i][1] == '\0') {
|
|
||||||
s->ind = s->i - s->n_args;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (argv[s->i][0] == '-' && argv[s->i][1] == '-') { /* "--" or a long option */
|
|
||||||
if (argv[s->i][2] == '\0') { /* a bare "--" */
|
|
||||||
ketopt_permute(argv, s->i, s->n_args);
|
|
||||||
++s->i, s->ind = s->i - s->n_args;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
s->opt = 0, opt = '?', s->pos = -1;
|
|
||||||
if (longopts) { /* parse long options */
|
|
||||||
int k, n_matches = 0;
|
|
||||||
const ko_longopt_t *o = 0;
|
|
||||||
for (j = 2; argv[s->i][j] != '\0' && argv[s->i][j] != '='; ++j) {} /* find the end of the option name */
|
|
||||||
for (k = 0; longopts[k].name != 0; ++k)
|
|
||||||
if (strncmp(&argv[s->i][2], longopts[k].name, j - 2) == 0)
|
|
||||||
++n_matches, o = &longopts[k];
|
|
||||||
if (n_matches == 1) {
|
|
||||||
s->opt = opt = o->val, s->longidx = (int)(o - longopts);
|
|
||||||
if (argv[s->i][j] == '=') s->arg = &argv[s->i][j + 1];
|
|
||||||
if (o->has_arg == 1 && argv[s->i][j] == '\0') {
|
|
||||||
if (s->i < argc - 1) s->arg = argv[++s->i];
|
|
||||||
else opt = ':'; /* missing option argument */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { /* a short option */
|
|
||||||
const char *p;
|
|
||||||
if (s->pos == 0) s->pos = 1;
|
|
||||||
opt = s->opt = argv[s->i][s->pos++];
|
|
||||||
p = strchr(ostr, opt);
|
|
||||||
if (p == 0) {
|
|
||||||
opt = '?'; /* unknown option */
|
|
||||||
}
|
|
||||||
else if (p[1] == ':') {
|
|
||||||
if (argv[s->i][s->pos] == 0) {
|
|
||||||
if (s->i < argc - 1) s->arg = argv[++s->i];
|
|
||||||
else opt = ':'; /* missing option argument */
|
|
||||||
}
|
|
||||||
else s->arg = &argv[s->i][s->pos];
|
|
||||||
s->pos = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (s->pos < 0 || argv[s->i][s->pos] == 0) {
|
|
||||||
++s->i, s->pos = 0;
|
|
||||||
if (s->n_args > 0) /* permute */
|
|
||||||
for (j = i0; j < s->i; ++j)
|
|
||||||
ketopt_permute(argv, j, s->n_args);
|
|
||||||
}
|
|
||||||
s->ind = s->i - s->n_args;
|
|
||||||
return opt;
|
|
||||||
}
|
|
354
Minetestmapper/parg.c
Normal file
354
Minetestmapper/parg.c
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
* parg - parse argv
|
||||||
|
*
|
||||||
|
* Written in 2015-2016 by Joergen Ibsen
|
||||||
|
*
|
||||||
|
* To the extent possible under law, the author(s) have dedicated all
|
||||||
|
* copyright and related and neighboring rights to this software to the
|
||||||
|
* public domain worldwide. This software is distributed without any
|
||||||
|
* warranty. <http://creativecommons.org/publicdomain/zero/1.0/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "parg.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if state is at end of argv.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
is_argv_end(const struct parg_state *ps, int argc, char *const argv[])
|
||||||
|
{
|
||||||
|
return ps->optind >= argc || argv[ps->optind] == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match nextchar against optstring.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
match_short(struct parg_state *ps, int argc, char *const argv[],
|
||||||
|
const char *optstring)
|
||||||
|
{
|
||||||
|
const char *p = strchr(optstring, *ps->nextchar);
|
||||||
|
|
||||||
|
if (p == NULL) {
|
||||||
|
ps->optopt = *ps->nextchar++;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no option argument, return option */
|
||||||
|
if (p[1] != ':') {
|
||||||
|
return *ps->nextchar++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If more characters, return as option argument */
|
||||||
|
if (ps->nextchar[1] != '\0') {
|
||||||
|
ps->optarg = &ps->nextchar[1];
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If option argument is optional, return option */
|
||||||
|
if (p[2] == ':') {
|
||||||
|
return *ps->nextchar++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Option argument required, so return next argv element */
|
||||||
|
if (is_argv_end(ps, argc, argv)) {
|
||||||
|
ps->optopt = *ps->nextchar++;
|
||||||
|
return optstring[0] == ':' ? ':' : '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
ps->optarg = argv[ps->optind++];
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match string at nextchar against longopts.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
match_long(struct parg_state *ps, int argc, char *const argv[],
|
||||||
|
const char *optstring,
|
||||||
|
const struct parg_option *longopts, int *longindex)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
int num_match = 0;
|
||||||
|
int match = -1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
len = strcspn(ps->nextchar, "=");
|
||||||
|
|
||||||
|
for (i = 0; longopts[i].name; ++i) {
|
||||||
|
if (strncmp(ps->nextchar, longopts[i].name, len) == 0) {
|
||||||
|
match = i;
|
||||||
|
num_match++;
|
||||||
|
/* Take if exact match */
|
||||||
|
if (longopts[i].name[len] == '\0') {
|
||||||
|
num_match = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return '?' on no or ambiguous match */
|
||||||
|
if (num_match != 1) {
|
||||||
|
ps->optopt = 0;
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(match != -1);
|
||||||
|
|
||||||
|
if (longindex) {
|
||||||
|
*longindex = match;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps->nextchar[len] == '=') {
|
||||||
|
/* Option argument present, check if extraneous */
|
||||||
|
if (longopts[match].has_arg == PARG_NOARG) {
|
||||||
|
ps->optopt = longopts[match].flag ? 0 : longopts[match].val;
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
return optstring[0] == ':' ? ':' : '?';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ps->optarg = &ps->nextchar[len + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (longopts[match].has_arg == PARG_REQARG) {
|
||||||
|
/* Option argument required, so return next argv element */
|
||||||
|
if (is_argv_end(ps, argc, argv)) {
|
||||||
|
ps->optopt = longopts[match].flag ? 0 : longopts[match].val;
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
return optstring[0] == ':' ? ':' : '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
ps->optarg = argv[ps->optind++];
|
||||||
|
}
|
||||||
|
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
|
||||||
|
if (longopts[match].flag != NULL) {
|
||||||
|
*longopts[match].flag = longopts[match].val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return longopts[match].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parg_init(struct parg_state *ps)
|
||||||
|
{
|
||||||
|
ps->optarg = NULL;
|
||||||
|
ps->optind = 1;
|
||||||
|
ps->optopt = '?';
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parg_getopt(struct parg_state *ps, int argc, char *const argv[],
|
||||||
|
const char *optstring)
|
||||||
|
{
|
||||||
|
return parg_getopt_long(ps, argc, argv, optstring, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parg_getopt_long(struct parg_state *ps, int argc, char *const argv[],
|
||||||
|
const char *optstring,
|
||||||
|
const struct parg_option *longopts, int *longindex)
|
||||||
|
{
|
||||||
|
assert(ps != NULL);
|
||||||
|
assert(argv != NULL);
|
||||||
|
assert(optstring != NULL);
|
||||||
|
|
||||||
|
ps->optarg = NULL;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance to next element if needed */
|
||||||
|
if (ps->nextchar == NULL || *ps->nextchar == '\0') {
|
||||||
|
if (is_argv_end(ps, argc, argv)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ps->nextchar = argv[ps->optind++];
|
||||||
|
|
||||||
|
/* Check for nonoption element (including '-') */
|
||||||
|
if (ps->nextchar[0] != '-' || ps->nextchar[1] == '\0') {
|
||||||
|
ps->optarg = ps->nextchar;
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for '--' */
|
||||||
|
if (ps->nextchar[1] == '-') {
|
||||||
|
if (ps->nextchar[2] == '\0') {
|
||||||
|
ps->nextchar = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (longopts != NULL) {
|
||||||
|
ps->nextchar += 2;
|
||||||
|
|
||||||
|
return match_long(ps, argc, argv, optstring,
|
||||||
|
longopts, longindex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ps->nextchar++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Match nextchar */
|
||||||
|
return match_short(ps, argc, argv, optstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reverse elements of `v` from `i` to `j`.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
reverse(char *v[], int i, int j)
|
||||||
|
{
|
||||||
|
while (j - i > 1) {
|
||||||
|
char *tmp = v[i];
|
||||||
|
v[i] = v[j - 1];
|
||||||
|
v[j - 1] = tmp;
|
||||||
|
++i;
|
||||||
|
--j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reorder elements of `argv` with no special cases.
|
||||||
|
*
|
||||||
|
* This function assumes there is no `--` element, and the last element
|
||||||
|
* is not an option missing a required argument.
|
||||||
|
*
|
||||||
|
* The algorithm is described here:
|
||||||
|
* http://hardtoc.com/2016/11/07/reordering-arguments.html
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parg_reorder_simple(int argc, char *argv[],
|
||||||
|
const char *optstring,
|
||||||
|
const struct parg_option *longopts)
|
||||||
|
{
|
||||||
|
struct parg_state ps;
|
||||||
|
int change;
|
||||||
|
int l = 0;
|
||||||
|
int m = 0;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
return argc;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
int nextind;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
parg_init(&ps);
|
||||||
|
|
||||||
|
nextind = ps.optind;
|
||||||
|
|
||||||
|
/* Parse until end of argument */
|
||||||
|
do {
|
||||||
|
c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL);
|
||||||
|
} while (ps.nextchar != NULL && *ps.nextchar != '\0');
|
||||||
|
|
||||||
|
change = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Find next non-option */
|
||||||
|
for (l = nextind; c != 1 && c != -1;) {
|
||||||
|
l = ps.optind;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL);
|
||||||
|
} while (ps.nextchar != NULL && *ps.nextchar != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find next option */
|
||||||
|
for (m = l; c == 1;) {
|
||||||
|
m = ps.optind;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL);
|
||||||
|
} while (ps.nextchar != NULL && *ps.nextchar != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find next non-option */
|
||||||
|
for (r = m; c != 1 && c != -1;) {
|
||||||
|
r = ps.optind;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL);
|
||||||
|
} while (ps.nextchar != NULL && *ps.nextchar != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find next option */
|
||||||
|
for (nextind = r; c == 1;) {
|
||||||
|
nextind = ps.optind;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL);
|
||||||
|
} while (ps.nextchar != NULL && *ps.nextchar != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m < r) {
|
||||||
|
change = 1;
|
||||||
|
reverse(argv, l, m);
|
||||||
|
reverse(argv, m, r);
|
||||||
|
reverse(argv, l, r);
|
||||||
|
}
|
||||||
|
} while (c != -1);
|
||||||
|
} while (change != 0);
|
||||||
|
|
||||||
|
return l + (r - m);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parg_reorder(int argc, char *argv[],
|
||||||
|
const char *optstring,
|
||||||
|
const struct parg_option *longopts)
|
||||||
|
{
|
||||||
|
struct parg_state ps;
|
||||||
|
int lastind;
|
||||||
|
int optend;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
assert(argv != NULL);
|
||||||
|
assert(optstring != NULL);
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
return argc;
|
||||||
|
}
|
||||||
|
|
||||||
|
parg_init(&ps);
|
||||||
|
|
||||||
|
/* Find end of normal arguments */
|
||||||
|
do {
|
||||||
|
lastind = ps.optind;
|
||||||
|
|
||||||
|
c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL);
|
||||||
|
|
||||||
|
/* Check for trailing option with error */
|
||||||
|
if ((c == '?' || c == ':') && is_argv_end(&ps, argc, argv)) {
|
||||||
|
lastind = ps.optind - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (c != -1);
|
||||||
|
|
||||||
|
optend = parg_reorder_simple(lastind, argv, optstring, longopts);
|
||||||
|
|
||||||
|
/* Rotate `--` or trailing option with error into position */
|
||||||
|
if (lastind < argc) {
|
||||||
|
reverse(argv, optend, lastind);
|
||||||
|
reverse(argv, optend, lastind + 1);
|
||||||
|
++optend;
|
||||||
|
}
|
||||||
|
|
||||||
|
return optend;
|
||||||
|
}
|
192
Minetestmapper/parg.h
Normal file
192
Minetestmapper/parg.h
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* parg - parse argv
|
||||||
|
*
|
||||||
|
* Written in 2015-2016 by Joergen Ibsen
|
||||||
|
*
|
||||||
|
* To the extent possible under law, the author(s) have dedicated all
|
||||||
|
* copyright and related and neighboring rights to this software to the
|
||||||
|
* public domain worldwide. This software is distributed without any
|
||||||
|
* warranty. <http://creativecommons.org/publicdomain/zero/1.0/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PARG_H_INCLUDED
|
||||||
|
#define PARG_H_INCLUDED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PARG_VER_MAJOR 1 /**< Major version number */
|
||||||
|
#define PARG_VER_MINOR 0 /**< Minor version number */
|
||||||
|
#define PARG_VER_PATCH 2 /**< Patch version number */
|
||||||
|
#define PARG_VER_STRING "1.0.2" /**< Version number as a string */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure containing state between calls to parser.
|
||||||
|
*
|
||||||
|
* @see parg_init
|
||||||
|
*/
|
||||||
|
struct parg_state {
|
||||||
|
const char *optarg; /**< Pointer to option argument, if any */
|
||||||
|
int optind; /**< Next index in argv to process */
|
||||||
|
int optopt; /**< Option value resulting in error, if any */
|
||||||
|
const char *nextchar; /**< Next character to process */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure for supplying long options to `parg_getopt_long()`.
|
||||||
|
*
|
||||||
|
* @see parg_getopt_long
|
||||||
|
*/
|
||||||
|
struct parg_option {
|
||||||
|
const char *name; /**< Name of option */
|
||||||
|
int has_arg; /**< Option argument status */
|
||||||
|
int *flag; /**< Pointer to flag variable */
|
||||||
|
int val; /**< Value of option */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Values for `has_arg` flag in `parg_option`.
|
||||||
|
*
|
||||||
|
* @see parg_option
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
PARG_NOARG, /**< No argument */
|
||||||
|
PARG_REQARG, /**< Required argument */
|
||||||
|
PARG_OPTARG /**< Optional argument */
|
||||||
|
} parg_arg_num;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize `ps`.
|
||||||
|
*
|
||||||
|
* Must be called before using state with a parser.
|
||||||
|
*
|
||||||
|
* @see parg_state
|
||||||
|
*
|
||||||
|
* @param ps pointer to state
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
parg_init(struct parg_state *ps);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse next short option in `argv`.
|
||||||
|
*
|
||||||
|
* Elements in `argv` that contain short options start with a single dash
|
||||||
|
* followed by one or more option characters, and optionally an option
|
||||||
|
* argument for the last option character. Examples are '`-d`', '`-ofile`',
|
||||||
|
* and '`-dofile`'.
|
||||||
|
*
|
||||||
|
* Consecutive calls to this function match the command-line arguments in
|
||||||
|
* `argv` against the short option characters in `optstring`.
|
||||||
|
*
|
||||||
|
* If an option character in `optstring` is followed by a colon, '`:`', the
|
||||||
|
* option requires an argument. If it is followed by two colons, the option
|
||||||
|
* may take an optional argument.
|
||||||
|
*
|
||||||
|
* If a match is found, `optarg` points to the option argument, if any, and
|
||||||
|
* the value of the option character is returned.
|
||||||
|
*
|
||||||
|
* If a match is found, but is missing a required option argument, `optopt`
|
||||||
|
* is set to the option character. If the first character in `optstring` is
|
||||||
|
* '`:`', then '`:`' is returned, otherwise '`?`' is returned.
|
||||||
|
*
|
||||||
|
* If no option character in `optstring` matches a short option, `optopt`
|
||||||
|
* is set to the option character, and '`?`' is returned.
|
||||||
|
*
|
||||||
|
* If an element of argv does not contain options (a nonoption element),
|
||||||
|
* `optarg` points to the element, and `1` is returned.
|
||||||
|
*
|
||||||
|
* An element consisting of a single dash, '`-`', is returned as a nonoption.
|
||||||
|
*
|
||||||
|
* Parsing stops and `-1` is returned, when the end of `argv` is reached, or
|
||||||
|
* if an element contains '`--`'.
|
||||||
|
*
|
||||||
|
* Works similarly to `getopt`, if `optstring` were prefixed by '`-`'.
|
||||||
|
*
|
||||||
|
* @param ps pointer to state
|
||||||
|
* @param argc number of elements in `argv`
|
||||||
|
* @param argv array of pointers to command-line arguments
|
||||||
|
* @param optstring string containing option characters
|
||||||
|
* @return option value on match, `1` on nonoption element, `-1` on end of
|
||||||
|
* arguments, '`?`' on unmatched option, '`?`' or '`:`' on option argument
|
||||||
|
* error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
parg_getopt(struct parg_state *ps, int argc, char *const argv[],
|
||||||
|
const char *optstring);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse next long or short option in `argv`.
|
||||||
|
*
|
||||||
|
* Elements in `argv` that contain a long option start with two dashes
|
||||||
|
* followed by a string, and optionally an equal sign and an option argument.
|
||||||
|
* Examples are '`--help`' and '`--size=5`'.
|
||||||
|
*
|
||||||
|
* If no exact match is found, an unambiguous prefix of a long option will
|
||||||
|
* match. For example, if '`foo`' and '`foobar`' are valid long options, then
|
||||||
|
* '`--fo`' is ambiguous and will not match, '`--foo`' matches exactly, and
|
||||||
|
* '`--foob`' is an unambiguous prefix and will match.
|
||||||
|
*
|
||||||
|
* If a long option match is found, and `flag` is `NULL`, `val` is returned.
|
||||||
|
*
|
||||||
|
* If a long option match is found, and `flag` is not `NULL`, `val` is stored
|
||||||
|
* in the variable `flag` points to, and `0` is returned.
|
||||||
|
*
|
||||||
|
* If a long option match is found, but is missing a required option argument,
|
||||||
|
* or has an option argument even though it takes none, `optopt` is set to
|
||||||
|
* `val` if `flag` is `NULL`, and `0` otherwise. If the first character in
|
||||||
|
* `optstring` is '`:`', then '`:`' is returned, otherwise '`?`' is returned.
|
||||||
|
*
|
||||||
|
* If `longindex` is not `NULL`, the index of the entry in `longopts` that
|
||||||
|
* matched is stored there.
|
||||||
|
*
|
||||||
|
* If no long option in `longopts` matches a long option, '`?`' is returned.
|
||||||
|
*
|
||||||
|
* Handling of nonoptions and short options is like `parg_getopt()`.
|
||||||
|
*
|
||||||
|
* If no short options are required, an empty string, `""`, should be passed
|
||||||
|
* as `optstring`.
|
||||||
|
*
|
||||||
|
* Works similarly to `getopt_long`, if `optstring` were prefixed by '`-`'.
|
||||||
|
*
|
||||||
|
* @see parg_getopt
|
||||||
|
*
|
||||||
|
* @param ps pointer to state
|
||||||
|
* @param argc number of elements in `argv`
|
||||||
|
* @param argv array of pointers to command-line arguments
|
||||||
|
* @param optstring string containing option characters
|
||||||
|
* @param longopts array of `parg_option` structures
|
||||||
|
* @param longindex pointer to variable to store index of matching option in
|
||||||
|
* @return option value on match, `0` for flag option, `1` on nonoption
|
||||||
|
* element, `-1` on end of arguments, '`?`' on unmatched or ambiguous option,
|
||||||
|
* '`?`' or '`:`' on option argument error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
parg_getopt_long(struct parg_state *ps, int argc, char *const argv[],
|
||||||
|
const char *optstring,
|
||||||
|
const struct parg_option *longopts, int *longindex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorder elements of `argv` so options appear first.
|
||||||
|
*
|
||||||
|
* If there are no long options, `longopts` may be `NULL`.
|
||||||
|
*
|
||||||
|
* The return value can be used as `argc` parameter for `parg_getopt()` and
|
||||||
|
* `parg_getopt_long()`.
|
||||||
|
*
|
||||||
|
* @param argc number of elements in `argv`
|
||||||
|
* @param argv array of pointers to command-line arguments
|
||||||
|
* @param optstring string containing option characters
|
||||||
|
* @param longopts array of `parg_option` structures
|
||||||
|
* @return index of first nonoption in `argv` on success, `-1` on error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
parg_reorder(int argc, char *argv[],
|
||||||
|
const char *optstring,
|
||||||
|
const struct parg_option *longopts);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* PARG_H_INCLUDED */
|
Loading…
x
Reference in New Issue
Block a user