Replace getopt/ketopt with parg
parent
0fed381201
commit
456cfb7f0f
|
@ -45,7 +45,8 @@ set(sources
|
|||
db-redis.h
|
||||
db-sqlite3.cpp
|
||||
db-sqlite3.h
|
||||
ketopt.h
|
||||
parg.h
|
||||
parg.c
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
@ -64,6 +65,7 @@ if(WIN32)
|
|||
include_directories(${SYSTEM_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
|
||||
set(leveldb_lib "")
|
||||
if(USE_LEVELDB)
|
||||
set(leveldb_lib ${LEVELDB_LIBRARY})
|
||||
|
@ -88,6 +90,7 @@ if(USE_REDIS)
|
|||
endif()
|
||||
|
||||
|
||||
#link_directories (../wingetopt)
|
||||
# Fügen Sie der ausführbaren Datei für dieses Projekt eine Quelle hinzu.
|
||||
add_executable (Minetestmapper ${sources})
|
||||
set_target_properties(Minetestmapper PROPERTIES COMPILE_FLAGS -DBUILDER_STATIC_DEFINE)
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "porting.h"
|
||||
#include "util.h"
|
||||
#include "version.h"
|
||||
#include "ketopt.h"
|
||||
#include "parg.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
@ -50,80 +50,82 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// 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' },
|
||||
{ "version", ko_no_argument, 'V' },
|
||||
{ "input", ko_required_argument, 'i' },
|
||||
{ "output", ko_required_argument, 'o' },
|
||||
{ "colors", ko_required_argument, 'C' },
|
||||
{ "heightmap-nodes", ko_required_argument, OPT_HEIGHTMAPNODESFILE },
|
||||
{ "heightmap-colors", ko_required_argument, OPT_HEIGHTMAPCOLORSFILE },
|
||||
{ "heightmap", ko_optional_argument, OPT_HEIGHTMAP },
|
||||
{ "heightmap-yscale", ko_required_argument, OPT_HEIGHTMAPYSCALE },
|
||||
{ "height-level-0", ko_required_argument, OPT_HEIGHT_LEVEL0 },
|
||||
{ "bgcolor", ko_required_argument, 'b' },
|
||||
{ "blockcolor", ko_required_argument, OPT_BLOCKCOLOR },
|
||||
{ "scalecolor", ko_required_argument, 's' },
|
||||
{ "origincolor", ko_required_argument, 'r' },
|
||||
{ "playercolor", ko_required_argument, 'p' },
|
||||
{ "draworigin", ko_no_argument, 'R' },
|
||||
{ "drawplayers", ko_no_argument, 'P' },
|
||||
{ "drawscale", ko_optional_argument, 'S' },
|
||||
{ "sidescale-interval", ko_required_argument, OPT_SCALEINTERVAL },
|
||||
{ "drawheightscale", ko_no_argument, OPT_DRAWHEIGHTSCALE },
|
||||
{ "heightscale-interval", ko_required_argument, OPT_SCALEINTERVAL },
|
||||
{ "drawalpha", ko_optional_argument, 'e' },
|
||||
{ "drawair", ko_no_argument, OPT_DRAWAIR },
|
||||
{ "drawnodes", ko_required_argument, OPT_DRAWNODES },
|
||||
{ "ignorenodes", ko_required_argument, OPT_DRAWNODES },
|
||||
{ "drawpoint", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawline", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawcircle", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawellipse", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawrectangle", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawarrow", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawtext", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawmappoint", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawmapline", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawmapcircle", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawmapellipse", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawmaprectangle", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawmaparrow", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "drawmaptext", ko_required_argument, OPT_DRAW_OBJECT },
|
||||
{ "noshading", ko_no_argument, 'H' },
|
||||
{ "geometry", ko_required_argument, 'g' },
|
||||
{ "cornergeometry", ko_required_argument, 'g' },
|
||||
{ "centergeometry", ko_required_argument, 'g' },
|
||||
{ "geometrymode", ko_required_argument, 'G' },
|
||||
{ "forcegeometry", ko_no_argument, 'G' },
|
||||
{ "min-y", ko_required_argument, 'a' },
|
||||
{ "max-y", ko_required_argument, 'c' },
|
||||
{ "backend", ko_required_argument, 'd' },
|
||||
{ "disable-blocklist-prefetch", ko_optional_argument, OPT_NO_BLOCKLIST_PREFETCH },
|
||||
{ "database-format", ko_required_argument, OPT_DATABASE_FORMAT },
|
||||
{ "prescan-world", ko_required_argument, OPT_PRESCAN_WORLD },
|
||||
{ "sqlite-cacheworldrow", ko_no_argument, OPT_SQLITE_CACHEWORLDROW },
|
||||
{ "sqlite3-limit-prescan-query-size", ko_optional_argument, OPT_SQLITE_LIMIT_PRESCAN_QUERY },
|
||||
{ "tiles", ko_required_argument, 't' },
|
||||
{ "tileorigin", ko_required_argument, 'T' },
|
||||
{ "tilecenter", ko_required_argument, 'T' },
|
||||
{ "tilebordercolor", ko_required_argument, 'B' },
|
||||
{ "scalefactor", ko_required_argument, OPT_SCALEFACTOR },
|
||||
{ "chunksize", ko_required_argument, OPT_CHUNKSIZE },
|
||||
{ "silence-suggestions", ko_required_argument, OPT_SILENCE_SUGGESTIONS },
|
||||
{ "verbose", ko_optional_argument, 'v' },
|
||||
{ "verbose-search-colors", ko_optional_argument, OPT_VERBOSE_SEARCH_COLORS },
|
||||
{ "progress", ko_no_argument, OPT_PROGRESS_INDICATOR },
|
||||
{ nullptr, 0, 0 }
|
||||
{ "help", PARG_NOARG, nullptr, 'h' },
|
||||
{ "version", PARG_NOARG, nullptr, 'V' },
|
||||
{ "input", PARG_REQARG, nullptr, 'i' },
|
||||
{ "output", PARG_REQARG, nullptr, 'o' },
|
||||
{ "colors", PARG_REQARG, nullptr, 'C' },
|
||||
{ "heightmap-nodes", PARG_REQARG, nullptr, OPT_HEIGHTMAPNODESFILE },
|
||||
{ "heightmap-colors", PARG_REQARG, nullptr, OPT_HEIGHTMAPCOLORSFILE },
|
||||
{ "heightmap", PARG_OPTARG, nullptr, OPT_HEIGHTMAP },
|
||||
{ "heightmap-yscale", PARG_REQARG, nullptr, OPT_HEIGHTMAPYSCALE },
|
||||
{ "height-level-0", PARG_REQARG, nullptr, OPT_HEIGHT_LEVEL0 },
|
||||
{ "bgcolor", PARG_REQARG, nullptr, 'b' },
|
||||
{ "blockcolor", PARG_REQARG, nullptr, OPT_BLOCKCOLOR },
|
||||
{ "scalecolor", PARG_REQARG, nullptr, 's' },
|
||||
{ "origincolor", PARG_REQARG, nullptr, 'r' },
|
||||
{ "playercolor", PARG_REQARG, nullptr, 'p' },
|
||||
{ "draworigin", PARG_NOARG, nullptr, 'R' },
|
||||
{ "drawplayers", PARG_NOARG, nullptr, 'P' },
|
||||
{ "drawscale", PARG_OPTARG, nullptr, 'S' },
|
||||
{ "sidescale-interval", PARG_REQARG, nullptr, OPT_SCALEINTERVAL },
|
||||
{ "drawheightscale", PARG_NOARG, nullptr, OPT_DRAWHEIGHTSCALE },
|
||||
{ "heightscale-interval", PARG_REQARG, nullptr, OPT_SCALEINTERVAL },
|
||||
{ "drawalpha", PARG_OPTARG, nullptr, 'e' },
|
||||
{ "drawair", PARG_NOARG, nullptr, OPT_DRAWAIR },
|
||||
{ "drawnodes", PARG_REQARG, nullptr, OPT_DRAWNODES },
|
||||
{ "ignorenodes", PARG_REQARG, nullptr, OPT_DRAWNODES },
|
||||
{ "drawpoint", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawline", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawcircle", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawellipse", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawrectangle", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawarrow", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawtext", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawmappoint", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawmapline", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawmapcircle", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawmapellipse", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawmaprectangle", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawmaparrow", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "drawmaptext", PARG_REQARG, nullptr, OPT_DRAW_OBJECT },
|
||||
{ "noshading", PARG_NOARG, nullptr, 'H' },
|
||||
{ "geometry", PARG_REQARG, nullptr, 'g' },
|
||||
{ "cornergeometry", PARG_REQARG, nullptr, 'g' },
|
||||
{ "centergeometry", PARG_REQARG, nullptr, 'g' },
|
||||
{ "geometrymode", PARG_REQARG, nullptr, 'G' },
|
||||
{ "forcegeometry", PARG_NOARG, nullptr, 'G' },
|
||||
{ "min-y", PARG_REQARG, nullptr, 'a' },
|
||||
{ "max-y", PARG_REQARG, nullptr, 'c' },
|
||||
{ "backend", PARG_REQARG, nullptr, 'd' },
|
||||
{ "disable-blocklist-prefetch", PARG_OPTARG, nullptr, OPT_NO_BLOCKLIST_PREFETCH },
|
||||
{ "database-format", PARG_REQARG, nullptr, OPT_DATABASE_FORMAT },
|
||||
{ "prescan-world", PARG_REQARG, nullptr, OPT_PRESCAN_WORLD },
|
||||
{ "sqlite-cacheworldrow", PARG_NOARG, nullptr, OPT_SQLITE_CACHEWORLDROW },
|
||||
{ "sqlite3-limit-prescan-query-size", PARG_OPTARG, nullptr, OPT_SQLITE_LIMIT_PRESCAN_QUERY },
|
||||
{ "tiles", PARG_REQARG, nullptr, 't' },
|
||||
{ "tileorigin", PARG_REQARG, nullptr, 'T' },
|
||||
{ "tilecenter", PARG_REQARG, nullptr, 'T' },
|
||||
{ "tilebordercolor", PARG_REQARG, nullptr, 'B' },
|
||||
{ "scalefactor", PARG_REQARG, nullptr, OPT_SCALEFACTOR },
|
||||
{ "chunksize", PARG_REQARG, nullptr, OPT_CHUNKSIZE },
|
||||
{ "silence-suggestions", PARG_REQARG, nullptr, OPT_SILENCE_SUGGESTIONS },
|
||||
{ "verbose", PARG_OPTARG, nullptr, 'v' },
|
||||
{ "verbose-search-colors", PARG_OPTARG, nullptr, OPT_VERBOSE_SEARCH_COLORS },
|
||||
{ "progress", PARG_NOARG, nullptr, OPT_PROGRESS_INDICATOR },
|
||||
{ nullptr, 0, nullptr, 0 }
|
||||
};
|
||||
|
||||
try {
|
||||
//int option_index = 0;
|
||||
ketopt_t opt = KETOPT_INIT;
|
||||
int option_index = 0;
|
||||
int c = 0;
|
||||
struct parg_state ps;
|
||||
|
||||
parg_init(&ps);
|
||||
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 (input.empty() || output.empty()) {
|
||||
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) {
|
||||
case '?':
|
||||
if (opt.opt == 0) // Unknown long option
|
||||
std::cerr << "Unknown Option: '" << argv[opt.ind - 1] << "'." << std::endl;
|
||||
else
|
||||
std::cerr << "Unknown Option: '-" << static_cast<char>(opt.opt) << "'." << std::endl;
|
||||
usage();
|
||||
if (option_index) {
|
||||
cout << "Comandline Error: Option '--" << long_options[option_index].name << "' does not take an argument: "
|
||||
<< argv[ps.optind - 1] << endl;
|
||||
}
|
||||
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;
|
||||
break;
|
||||
case ':':
|
||||
if (opt.longidx != -1)
|
||||
std::cerr << "Missing Argument: --'" << long_options[opt.longidx].name << "'." << std::endl;
|
||||
else
|
||||
std::cerr << "Missing Argument: -'" << opt.opt << "'." << std::endl;
|
||||
usage();
|
||||
cout << "Comandline Error: Option does not take an argument '" << argv[ps.optind - 1]<< "'" << endl;
|
||||
return EXIT_FAILURE;
|
||||
break;
|
||||
case 'h':
|
||||
|
@ -158,29 +162,29 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
return 0;
|
||||
break;
|
||||
case 'i':
|
||||
input = opt.arg;
|
||||
input = ps.optarg;
|
||||
break;
|
||||
case 'o':
|
||||
output = opt.arg;
|
||||
output = ps.optarg;
|
||||
break;
|
||||
case 'C':
|
||||
nodeColorsFile = opt.arg;
|
||||
nodeColorsFile = ps.optarg;
|
||||
break;
|
||||
case OPT_HEIGHTMAPNODESFILE:
|
||||
heightMapNodesFile = opt.arg;
|
||||
heightMapNodesFile = ps.optarg;
|
||||
break;
|
||||
case OPT_HEIGHTMAPCOLORSFILE:
|
||||
heightMapColorsFile = opt.arg;
|
||||
heightMapColorsFile = ps.optarg;
|
||||
break;
|
||||
case 'b':
|
||||
generator.setBgColor(Color(opt.arg, 0));
|
||||
generator.setBgColor(Color(ps.optarg, 0));
|
||||
break;
|
||||
case OPT_NO_BLOCKLIST_PREFETCH:
|
||||
if (opt.arg && *opt.arg) {
|
||||
if (strlower(opt.arg) == "force")
|
||||
if (ps.optarg && *ps.optarg) {
|
||||
if (strlower(ps.optarg) == "force")
|
||||
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetchForced);
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -190,54 +194,54 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
}
|
||||
break;
|
||||
case OPT_DATABASE_FORMAT: {
|
||||
std::string option = strlower(opt.arg);
|
||||
if (option == "minetest-i64")
|
||||
std::string opt = strlower(ps.optarg);
|
||||
if (opt == "minetest-i64")
|
||||
generator.setDBFormat(BlockPos::I64, false);
|
||||
else if (option == "freeminer-axyz")
|
||||
else if (opt == "freeminer-axyz")
|
||||
generator.setDBFormat(BlockPos::AXYZ, false);
|
||||
else if (option == "mixed")
|
||||
else if (opt == "mixed")
|
||||
generator.setDBFormat(BlockPos::Unknown, false);
|
||||
else if (option == "query")
|
||||
else if (opt == "query")
|
||||
generator.setDBFormat(BlockPos::Unknown, true);
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case OPT_PRESCAN_WORLD: {
|
||||
std::string option = strlower(opt.arg);
|
||||
std::string opt = strlower(ps.optarg);
|
||||
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::Prefetch);
|
||||
if (option == "disabled-force")
|
||||
if (opt == "disabled-force")
|
||||
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetchForced);
|
||||
else if (option == "disabled")
|
||||
else if (opt == "disabled")
|
||||
generator.setGenerateNoPrefetch(TileGenerator::BlockListPrefetch::NoPrefetch);
|
||||
else if (option == "auto")
|
||||
else if (opt == "auto")
|
||||
generator.setScanEntireWorld(false);
|
||||
else if (option == "full")
|
||||
else if (opt == "full")
|
||||
generator.setScanEntireWorld(true);
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case OPT_SQLITE_LIMIT_PRESCAN_QUERY:
|
||||
if (!opt.arg || !*opt.arg) {
|
||||
if (!ps.optarg || !*ps.optarg) {
|
||||
#ifdef USE_SQLITE3
|
||||
DBSQLite3::setLimitBlockListQuerySize();
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (!isdigit(opt.arg[0])) {
|
||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name << "': must be a positive number" << std::endl;
|
||||
if (!isdigit(ps.optarg[0])) {
|
||||
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': must be a positive number" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#ifdef USE_SQLITE3
|
||||
int size = atoi(opt.arg);
|
||||
int size = atoi(ps.optarg);
|
||||
DBSQLite3::setLimitBlockListQuerySize(size);
|
||||
#endif
|
||||
}
|
||||
|
@ -245,9 +249,9 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
case OPT_HEIGHTMAP:
|
||||
generator.setHeightMap(true);
|
||||
heightMap = true;
|
||||
if (opt.arg && *opt.arg) {
|
||||
if (ps.optarg && *ps.optarg) {
|
||||
loadHeightMapColorsFile = false;
|
||||
std::string color = strlower(opt.arg);
|
||||
std::string color = strlower(ps.optarg);
|
||||
if (color == "grey" || color == "gray")
|
||||
generator.setHeightMapColor(Color(0, 0, 0), Color(255, 255, 255));
|
||||
else if (color == "black")
|
||||
|
@ -263,41 +267,41 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
}
|
||||
break;
|
||||
case OPT_HEIGHTMAPYSCALE:
|
||||
if (isdigit(opt.arg[0]) || ((opt.arg[0] == '-' || opt.arg[0] == '+') && isdigit(opt.arg[1]))) {
|
||||
float scale = static_cast<float>(atof(opt.arg));
|
||||
if (isdigit(ps.optarg[0]) || ((ps.optarg[0] == '-' || ps.optarg[0] == '+') && isdigit(ps.optarg[1]))) {
|
||||
float scale = static_cast<float>(atof(ps.optarg));
|
||||
generator.setHeightMapYScale(scale);
|
||||
}
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case OPT_HEIGHT_LEVEL0:
|
||||
if (isdigit(opt.arg[0]) || ((opt.arg[0] == '-' || opt.arg[0] == '+') && isdigit(opt.arg[1]))) {
|
||||
int level = atoi(opt.arg);
|
||||
if (isdigit(ps.optarg[0]) || ((ps.optarg[0] == '-' || ps.optarg[0] == '+') && isdigit(ps.optarg[1]))) {
|
||||
int level = atoi(ps.optarg);
|
||||
generator.setSeaLevel(level);
|
||||
}
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case OPT_BLOCKCOLOR:
|
||||
generator.setBlockDefaultColor(Color(opt.arg, 0));
|
||||
generator.setBlockDefaultColor(Color(ps.optarg, 0));
|
||||
break;
|
||||
case 's':
|
||||
generator.setScaleColor(Color(opt.arg, 0));
|
||||
generator.setScaleColor(Color(ps.optarg, 0));
|
||||
break;
|
||||
case 'r':
|
||||
generator.setOriginColor(Color(opt.arg, 1));
|
||||
generator.setOriginColor(Color(ps.optarg, 1));
|
||||
break;
|
||||
case 'p':
|
||||
generator.setPlayerColor(Color(opt.arg, 1));
|
||||
generator.setPlayerColor(Color(ps.optarg, 1));
|
||||
break;
|
||||
case 'B':
|
||||
generator.setTileBorderColor(Color(opt.arg, 0));
|
||||
generator.setTileBorderColor(Color(ps.optarg, 0));
|
||||
break;
|
||||
case 'R':
|
||||
generator.setDrawOrigin(true);
|
||||
|
@ -306,19 +310,19 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
generator.setDrawPlayers(true);
|
||||
break;
|
||||
case 'S':
|
||||
if (opt.arg && *opt.arg) {
|
||||
std::string option = strlower(opt.arg);
|
||||
if (option == "left")
|
||||
if (ps.optarg && *ps.optarg) {
|
||||
std::string opt = strlower(ps.optarg);
|
||||
if (opt == "left")
|
||||
generator.setDrawScale(DRAWSCALE_LEFT);
|
||||
else if (option == "top")
|
||||
else if (opt == "top")
|
||||
generator.setDrawScale(DRAWSCALE_TOP);
|
||||
else if (option == "left,top")
|
||||
else if (opt == "left,top")
|
||||
generator.setDrawScale(DRAWSCALE_LEFT | DRAWSCALE_TOP);
|
||||
else if (option == "top,left")
|
||||
else if (opt == "top,left")
|
||||
generator.setDrawScale(DRAWSCALE_LEFT | DRAWSCALE_TOP);
|
||||
else {
|
||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name
|
||||
<< "': '" << opt.arg << "' (expected: left,top)" << std::endl;
|
||||
std::cerr << "Invalid parameter to '" << long_options[option_index].name
|
||||
<< "': '" << ps.optarg << "' (expected: left,top)" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -332,29 +336,29 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
break;
|
||||
case OPT_SCALEINTERVAL: {
|
||||
istringstream arg;
|
||||
arg.str(opt.arg);
|
||||
arg.str(ps.optarg);
|
||||
int major;
|
||||
int minor;
|
||||
char sep;
|
||||
arg >> major;
|
||||
if (major < 0 || !isdigit(*opt.arg) || arg.fail()) {
|
||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name
|
||||
<< "': '" << opt.arg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||
if (major < 0 || !isdigit(*ps.optarg) || arg.fail()) {
|
||||
std::cerr << "Invalid parameter to '" << long_options[option_index].name
|
||||
<< "': '" << ps.optarg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
arg >> std::ws >> sep >> std::ws;
|
||||
if (!arg.fail()) {
|
||||
if ((sep != ',' && sep != ':') || !isdigit(arg.peek())) {
|
||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name
|
||||
<< "': '" << opt.arg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||
std::cerr << "Invalid parameter to '" << long_options[option_index].name
|
||||
<< "': '" << ps.optarg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
arg >> minor;
|
||||
if (minor < 0) {
|
||||
std::cerr << "Invalid parameter to '" << long_options[opt.ind].name
|
||||
<< "': '" << opt.arg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||
std::cerr << "Invalid parameter to '" << long_options[option_index].name
|
||||
<< "': '" << ps.optarg << "' (expected: <major>[,<minor>]" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -364,7 +368,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
}
|
||||
if (minor && sep == ':') {
|
||||
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;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -372,25 +376,25 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
}
|
||||
if ((minor % major) == 0)
|
||||
minor = 0;
|
||||
if (long_options[opt.ind].name[0] == 's') {
|
||||
if (long_options[option_index].name[0] == 's') {
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case OPT_SILENCE_SUGGESTIONS: {
|
||||
for (size_t i = 0; i < strlen(opt.arg); i++) {
|
||||
opt.arg[i] = tolower(opt.arg[i]);
|
||||
if (opt.arg[i] == ',')
|
||||
opt.arg[i] = ' ';
|
||||
string optarg = strlower(ps.optarg);
|
||||
for(char &c : optarg) {
|
||||
if (c == ',')
|
||||
c = ' ';
|
||||
}
|
||||
std::istringstream iss(opt.arg);
|
||||
std::istringstream iss(optarg);
|
||||
std::string flag;
|
||||
iss >> std::skipws >> flag;
|
||||
while (!iss.fail()) {
|
||||
|
@ -407,18 +411,18 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
#endif
|
||||
}
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
iss >> flag;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 'v':
|
||||
if (opt.arg && isdigit(opt.arg[0]) && opt.arg[1] == '\0') {
|
||||
generator.verboseStatistics = opt.arg[0] - '0';
|
||||
generator.verboseCoordinates = opt.arg[0] - '0';
|
||||
if (ps.optarg && isdigit(ps.optarg[0]) && ps.optarg[1] == '\0') {
|
||||
generator.verboseStatistics = ps.optarg[0] - '0';
|
||||
generator.verboseCoordinates = ps.optarg[0] - '0';
|
||||
}
|
||||
else {
|
||||
generator.verboseStatistics = 1;
|
||||
|
@ -426,29 +430,30 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
}
|
||||
break;
|
||||
case OPT_VERBOSE_SEARCH_COLORS:
|
||||
if (opt.arg && isdigit(opt.arg[0]) && opt.arg[1] == '\0') {
|
||||
generator.verboseReadColors = opt.arg[0] - '0';
|
||||
if (ps.optarg && isdigit(ps.optarg[0]) && ps.optarg[1] == '\0') {
|
||||
generator.verboseReadColors = ps.optarg[0] - '0';
|
||||
}
|
||||
else {
|
||||
generator.verboseReadColors++;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
// Todo: Unnecessary calls to strlower. Optimize
|
||||
generator.setDrawAlpha(true);
|
||||
if (!opt.arg || !*opt.arg)
|
||||
if (!ps.optarg || !*ps.optarg)
|
||||
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
|
||||
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
|
||||
PixelAttribute::setMixMode(PixelAttribute::AlphaMixCumulativeDarken);
|
||||
else if (strlower(opt.arg) == "average")
|
||||
else if (strlower(ps.optarg) == "average")
|
||||
PixelAttribute::setMixMode(PixelAttribute::AlphaMixAverage);
|
||||
else if (strlower(opt.arg) == "none")
|
||||
else if (strlower(ps.optarg) == "none")
|
||||
generator.setDrawAlpha(false);
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -457,12 +462,12 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
generator.setDrawAir(true);
|
||||
break;
|
||||
case OPT_DRAWNODES: {
|
||||
bool draw = long_options[opt.ind].name[0] == 'd';
|
||||
for (char *c = opt.arg; *c; c++) {
|
||||
*c = tolower(*c);
|
||||
if (*c == ',') *c = ' ';
|
||||
bool draw = long_options[option_index].name[0] == 'd';
|
||||
string optarg = strlower(ps.optarg);
|
||||
for (char &c : optarg){
|
||||
if (c == ',') c = ' ';
|
||||
}
|
||||
istringstream iss(opt.arg);
|
||||
istringstream iss(optarg);
|
||||
string flag;
|
||||
iss >> std::skipws >> flag;
|
||||
while (!iss.fail()) {
|
||||
|
@ -478,14 +483,14 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
else if (flag == "air")
|
||||
generator.setDrawAir(enable);
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
iss >> flag;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 'H':
|
||||
generator.setShading(false);
|
||||
break;
|
||||
|
@ -501,48 +506,48 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
break;
|
||||
case 'a': {
|
||||
istringstream iss;
|
||||
iss.str(opt.arg);
|
||||
iss.str(ps.optarg);
|
||||
int miny;
|
||||
iss >> miny;
|
||||
generator.setMinY(miny);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 'c': {
|
||||
istringstream iss;
|
||||
iss.str(opt.arg);
|
||||
iss.str(ps.optarg);
|
||||
int maxy;
|
||||
iss >> maxy;
|
||||
generator.setMaxY(maxy);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case OPT_CHUNKSIZE: {
|
||||
istringstream iss;
|
||||
iss.str(opt.arg);
|
||||
iss.str(ps.optarg);
|
||||
int size;
|
||||
iss >> size;
|
||||
if (iss.fail() || size < 0) {
|
||||
std::cerr << "Invalid chunk size (" << opt.arg << ")" << std::endl;
|
||||
std::cerr << "Invalid chunk size (" << ps.optarg << ")" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
generator.setChunkSize(size);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case OPT_SCALEFACTOR: {
|
||||
istringstream arg;
|
||||
arg.str(opt.arg);
|
||||
arg.str(ps.optarg);
|
||||
int one;
|
||||
char colon;
|
||||
int factor = 1;
|
||||
arg >> one >> std::ws;
|
||||
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;
|
||||
}
|
||||
if (!arg.eof()) {
|
||||
arg >> colon >> factor >> std::ws;
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -553,10 +558,10 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
}
|
||||
generator.setScaleFactor(factor);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 't': {
|
||||
istringstream tilesize;
|
||||
tilesize.str(strlower(opt.arg));
|
||||
tilesize.str(strlower(ps.optarg));
|
||||
if (tilesize.str() == "block") {
|
||||
generator.setTileSize(BLOCK_SIZE, BLOCK_SIZE);
|
||||
generator.setTileOrigin(TILECORNER_AT_WORLDCENTER, TILECORNER_AT_WORLDCENTER);
|
||||
|
@ -570,7 +575,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
char c;
|
||||
tilesize >> size;
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -578,7 +583,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
tilesize >> c >> border;
|
||||
if (!tilesize.fail()) {
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -586,11 +591,11 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 'T': {
|
||||
bool origin = long_options[opt.ind].name[4] == 'o';
|
||||
bool origin = long_options[option_index].name[4] == 'o';
|
||||
istringstream iss;
|
||||
iss.str(strlower(opt.arg));
|
||||
iss.str(strlower(ps.optarg));
|
||||
NodeCoord coord;
|
||||
if (iss.str() == "world") {
|
||||
if (origin)
|
||||
|
@ -607,7 +612,7 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
else {
|
||||
bool result = true;
|
||||
if (!parseCoordinates(iss, coord, 2, 0, ',')) {
|
||||
iss.str(opt.arg);
|
||||
iss.str(ps.optarg);
|
||||
result = parseCoordinates(iss, coord, 2, 0, ':');
|
||||
}
|
||||
if (result) {
|
||||
|
@ -621,15 +626,15 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 'G':
|
||||
if (long_options[opt.ind].name[0] == 'f') {
|
||||
if (long_options[option_index].name[0] == 'f') {
|
||||
// '--forcegeometry'
|
||||
// Old behavior - for compatibility.
|
||||
generator.setShrinkGeometry(false);
|
||||
|
@ -637,13 +642,14 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
if (!foundGeometrySpec)
|
||||
generator.setBlockGeometry(true);
|
||||
}
|
||||
else if (opt.arg && *opt.arg) {
|
||||
for (char *c = opt.arg; *c; c++) {
|
||||
*c = tolower(*c);
|
||||
if (*c == ',') *c = ' ';
|
||||
else if (ps.optarg && *ps.optarg) {
|
||||
string optarg = strlower(ps.optarg);
|
||||
for (char &c : optarg) {
|
||||
if (c == ',')
|
||||
c = ' ';
|
||||
}
|
||||
istringstream iss;
|
||||
iss.str(opt.arg);
|
||||
iss.str(optarg);
|
||||
string flag;
|
||||
iss >> std::skipws >> flag;
|
||||
while (!iss.fail()) {
|
||||
|
@ -671,23 +677,23 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
break;
|
||||
case 'g': {
|
||||
istringstream iss;
|
||||
iss.str(opt.arg);
|
||||
iss.str(ps.optarg);
|
||||
NodeCoord coord1;
|
||||
NodeCoord coord2;
|
||||
bool legacy;
|
||||
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;
|
||||
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;
|
||||
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();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Set defaults
|
||||
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'
|
||||
generator.setBlockGeometry(true);
|
||||
generator.setShrinkGeometry(true);
|
||||
|
@ -708,11 +714,11 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
generator.setGeometry(coord1, coord2);
|
||||
foundGeometrySpec = true;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case OPT_DRAW_OBJECT: {
|
||||
TileGenerator::DrawObject drawObject;
|
||||
drawObject.world = long_options[opt.ind].name[4] != 'm';
|
||||
char object = long_options[opt.ind].name[4 + (drawObject.world ? 0 : 3)];
|
||||
drawObject.world = long_options[option_index].name[4] != 'm';
|
||||
char object = long_options[option_index].name[4 + (drawObject.world ? 0 : 3)];
|
||||
switch (object) {
|
||||
case 'p':
|
||||
drawObject.type = TileGenerator::DrawObject::Point;
|
||||
|
@ -735,14 +741,14 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
break;
|
||||
default:
|
||||
std::cerr << "Internal error: unrecognised object ("
|
||||
<< long_options[opt.ind].name
|
||||
<< long_options[option_index].name
|
||||
<< ")" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
istringstream iss;
|
||||
iss.str(opt.arg);
|
||||
iss.str(ps.optarg);
|
||||
NodeCoord coord1;
|
||||
NodeCoord coord2;
|
||||
NodeCoord dimensions;
|
||||
|
@ -756,8 +762,8 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
needDimensions = FuzzyBool::Yes;
|
||||
if (!parseGeometry(iss, coord1, coord2, dimensions, legacy, centered, 2, needDimensions)) {
|
||||
std::cerr << "Invalid drawing geometry specification for "
|
||||
<< long_options[opt.ind].name
|
||||
<< " '" << opt.arg << "'" << std::endl;
|
||||
<< long_options[option_index].name
|
||||
<< " '" << ps.optarg << "'" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -800,8 +806,8 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
iss >> std::ws >> colorStr;
|
||||
if (iss.fail()) {
|
||||
std::cerr << "Missing color for "
|
||||
<< long_options[opt.ind].name
|
||||
<< " '" << opt.arg << "'" << std::endl;
|
||||
<< long_options[option_index].name
|
||||
<< " '" << ps.optarg << "'" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -813,8 +819,8 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
std::getline(iss, localizedText);
|
||||
if (localizedText.empty() || iss.fail()) {
|
||||
std::cerr << "Invalid or missing text for "
|
||||
<< long_options[opt.ind].name
|
||||
<< " '" << opt.arg << "'" << std::endl;
|
||||
<< long_options[option_index].name
|
||||
<< " '" << ps.optarg << "'" << std::endl;
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -848,11 +854,13 @@ int Mapper::start(int argc, char *argv[]) {
|
|||
generator.drawObject(drawObject);
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 'd':
|
||||
generator.setBackend(strlower(opt.arg));
|
||||
generator.setBackend(strlower(ps.optarg));
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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…
Reference in New Issue