Browse Source

Simplified argument parsing

Chlumsky 1 year ago
parent
commit
937f31ff41
2 changed files with 70 additions and 109 deletions
  1. 3 3
      README.md
  2. 67 106
      main.cpp

+ 3 - 3
README.md

@@ -15,7 +15,7 @@ The following comparison demonstrates the improvement in image quality.
 ![demo-sdf32](https://user-images.githubusercontent.com/18639794/106391906-e7aadc00-63ef-11eb-8f84-d402d0dd9174.png)
 ![demo-sdf32](https://user-images.githubusercontent.com/18639794/106391906-e7aadc00-63ef-11eb-8f84-d402d0dd9174.png)
 
 
 - To learn more about this method, you can read my [Master's thesis](https://github.com/Chlumsky/msdfgen/files/3050967/thesis.pdf).
 - To learn more about this method, you can read my [Master's thesis](https://github.com/Chlumsky/msdfgen/files/3050967/thesis.pdf).
-- Check out my [MSDF-Atlas-Gen](https://github.com/Chlumsky/msdf-atlas-gen) if you want to generate entire glyph atlases for text rendering.
+- Check out my [MSDF-Atlas-Gen](https://github.com/Chlumsky/msdf-atlas-gen) if you want to generate entire font atlases for text rendering.
 - See what's new in the [changelog](CHANGELOG.md).
 - See what's new in the [changelog](CHANGELOG.md).
 
 
 ## Getting started
 ## Getting started
@@ -68,7 +68,7 @@ The complete list of available options can be printed with **-help**.
 Some of the important ones are:
 Some of the important ones are:
  - **-o \<filename\>** &ndash; specifies the output file name. The desired format will be deduced from the extension
  - **-o \<filename\>** &ndash; specifies the output file name. The desired format will be deduced from the extension
    (png, bmp, tif, txt, bin). Otherwise, use -format.
    (png, bmp, tif, txt, bin). Otherwise, use -format.
- - **-size \<width\> \<height\>** &ndash; specifies the dimensions of the output distance field (in pixels).
+ - **-dimensions \<width\> \<height\>** &ndash; specifies the dimensions of the output distance field (in pixels).
  - **-range \<range\>**, **-pxrange \<range\>** &ndash; specifies the width of the range around the shape
  - **-range \<range\>**, **-pxrange \<range\>** &ndash; specifies the width of the range around the shape
    between the minimum and maximum representable signed distance in shape units or distance field pixels, respectivelly.
    between the minimum and maximum representable signed distance in shape units or distance field pixels, respectivelly.
  - **-scale \<scale\>** &ndash; sets the scale used to convert shape units to distance field pixels.
  - **-scale \<scale\>** &ndash; sets the scale used to convert shape units to distance field pixels.
@@ -87,7 +87,7 @@ Some of the important ones are:
 
 
 For example,
 For example,
 ```
 ```
-msdfgen.exe msdf -font C:\Windows\Fonts\arialbd.ttf 'M' -o msdf.png -size 32 32 -pxrange 4 -autoframe -testrender render.png 1024 1024
+msdfgen.exe msdf -font C:\Windows\Fonts\arialbd.ttf 'M' -o msdf.png -dimensions 32 32 -pxrange 4 -autoframe -testrender render.png 1024 1024
 ```
 ```
 
 
 will take the glyph capital M from the Arial Bold typeface, generate a 32&times;32 multi-channel distance field
 will take the glyph capital M from the Arial Bold typeface, generate a 32&times;32 multi-channel distance field

+ 67 - 106
main.cpp

@@ -394,6 +394,8 @@ static const char *const helpText =
         "\tAutomatically scales (unless specified) and translates the shape to fit.\n"
         "\tAutomatically scales (unless specified) and translates the shape to fit.\n"
     "  -coloringstrategy <simple / inktrap / distance>\n"
     "  -coloringstrategy <simple / inktrap / distance>\n"
         "\tSelects the strategy of the edge coloring heuristic.\n"
         "\tSelects the strategy of the edge coloring heuristic.\n"
+    "  -dimensions <width> <height>\n"
+        "\tSets the dimensions of the output image.\n"
     "  -distanceshift <shift>\n"
     "  -distanceshift <shift>\n"
         "\tShifts all normalized distances in the output distance field by this value.\n"
         "\tShifts all normalized distances in the output distance field by this value.\n"
     "  -edgecolors <sequence>\n"
     "  -edgecolors <sequence>\n"
@@ -453,8 +455,6 @@ static const char *const helpText =
 #endif
 #endif
     "  -seed <n>\n"
     "  -seed <n>\n"
         "\tSets the random seed for edge coloring heuristic.\n"
         "\tSets the random seed for edge coloring heuristic.\n"
-    "  -size <width> <height>\n"
-        "\tSets the dimensions of the output image.\n"
     "  -stdout\n"
     "  -stdout\n"
         "\tPrints the output instead of storing it in a file. Only text formats are supported.\n"
         "\tPrints the output instead of storing it in a file. Only text formats are supported.\n"
     "  -testrender <filename." DEFAULT_IMAGE_EXTENSION "> <width> <height>\n"
     "  -testrender <filename." DEFAULT_IMAGE_EXTENSION "> <width> <height>\n"
@@ -580,8 +580,10 @@ int main(int argc, const char *const *argv) {
     bool suggestHelp = false;
     bool suggestHelp = false;
     while (argPos < argc) {
     while (argPos < argc) {
         const char *arg = argv[argPos];
         const char *arg = argv[argPos];
-        #define ARG_CASE(s, p) if (!strcmp(arg, s) && argPos+(p) < argc)
+        #define ARG_CASE(s, p) if ((!strcmp(arg, s)) && argPos+(p) < argc && (++argPos, true))
+        #define ARG_CASE_OR ) || !strcmp(arg,
         #define ARG_MODE(s, m) if (!strcmp(arg, s)) { mode = m; ++argPos; continue; }
         #define ARG_MODE(s, m) if (!strcmp(arg, s)) { mode = m; ++argPos; continue; }
+        #define ARG_IS(s) (!strcmp(argv[argPos], s))
         #define SET_FORMAT(fmt, ext) do { format = fmt; if (!outputSpecified) output = "output." ext; } while (false)
         #define SET_FORMAT(fmt, ext) do { format = fmt; if (!outputSpecified) output = "output." ext; } while (false)
 
 
         // Accept arguments prefixed with -- instead of -
         // Accept arguments prefixed with -- instead of -
@@ -597,8 +599,7 @@ int main(int argc, const char *const *argv) {
     #if defined(MSDFGEN_EXTENSIONS) && !defined(MSDFGEN_DISABLE_SVG)
     #if defined(MSDFGEN_EXTENSIONS) && !defined(MSDFGEN_DISABLE_SVG)
         ARG_CASE("-svg", 1) {
         ARG_CASE("-svg", 1) {
             inputType = SVG;
             inputType = SVG;
-            input = argv[argPos+1];
-            argPos += 2;
+            input = argv[argPos++];
             continue;
             continue;
         }
         }
     #endif
     #endif
@@ -609,9 +610,9 @@ int main(int argc, const char *const *argv) {
             #ifndef MSDFGEN_DISABLE_VARIABLE_FONTS
             #ifndef MSDFGEN_DISABLE_VARIABLE_FONTS
                 || (!strcmp(arg, "-varfont") && (inputType = VAR_FONT, true))
                 || (!strcmp(arg, "-varfont") && (inputType = VAR_FONT, true))
             #endif
             #endif
-        )) {
-            input = argv[argPos+1];
-            const char *charArg = argv[argPos+2];
+        ) && (++argPos, true)) {
+            input = argv[argPos++];
+            const char *charArg = argv[argPos++];
             unsigned gi;
             unsigned gi;
             switch (charArg[0]) {
             switch (charArg[0]) {
                 case 'G': case 'g':
                 case 'G': case 'g':
@@ -626,7 +627,6 @@ int main(int argc, const char *const *argv) {
                 default:
                 default:
                     parseUnicode(unicode, charArg);
                     parseUnicode(unicode, charArg);
             }
             }
-            argPos += 3;
             continue;
             continue;
         }
         }
     #else
     #else
@@ -642,309 +642,271 @@ int main(int argc, const char *const *argv) {
     #endif
     #endif
         ARG_CASE("-defineshape", 1) {
         ARG_CASE("-defineshape", 1) {
             inputType = DESCRIPTION_ARG;
             inputType = DESCRIPTION_ARG;
-            input = argv[argPos+1];
-            argPos += 2;
+            input = argv[argPos++];
             continue;
             continue;
         }
         }
         ARG_CASE("-stdin", 0) {
         ARG_CASE("-stdin", 0) {
             inputType = DESCRIPTION_STDIN;
             inputType = DESCRIPTION_STDIN;
             input = "stdin";
             input = "stdin";
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-shapedesc", 1) {
         ARG_CASE("-shapedesc", 1) {
             inputType = DESCRIPTION_FILE;
             inputType = DESCRIPTION_FILE;
-            input = argv[argPos+1];
-            argPos += 2;
+            input = argv[argPos++];
             continue;
             continue;
         }
         }
-        ARG_CASE("-o", 1) {
-            output = argv[argPos+1];
+        ARG_CASE("-o" ARG_CASE_OR "-out" ARG_CASE_OR "-output" ARG_CASE_OR "-imageout", 1) {
+            output = argv[argPos++];
             outputSpecified = true;
             outputSpecified = true;
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-stdout", 0) {
         ARG_CASE("-stdout", 0) {
             output = NULL;
             output = NULL;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-legacy", 0) {
         ARG_CASE("-legacy", 0) {
             legacyMode = true;
             legacyMode = true;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-nopreprocess", 0) {
         ARG_CASE("-nopreprocess", 0) {
             geometryPreproc = NO_PREPROCESS;
             geometryPreproc = NO_PREPROCESS;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-windingpreprocess", 0) {
         ARG_CASE("-windingpreprocess", 0) {
             geometryPreproc = WINDING_PREPROCESS;
             geometryPreproc = WINDING_PREPROCESS;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-preprocess", 0) {
         ARG_CASE("-preprocess", 0) {
             geometryPreproc = FULL_PREPROCESS;
             geometryPreproc = FULL_PREPROCESS;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-nooverlap", 0) {
         ARG_CASE("-nooverlap", 0) {
             generatorConfig.overlapSupport = false;
             generatorConfig.overlapSupport = false;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-overlap", 0) {
         ARG_CASE("-overlap", 0) {
             generatorConfig.overlapSupport = true;
             generatorConfig.overlapSupport = true;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-noscanline", 0) {
         ARG_CASE("-noscanline", 0) {
             scanlinePass = false;
             scanlinePass = false;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-scanline", 0) {
         ARG_CASE("-scanline", 0) {
             scanlinePass = true;
             scanlinePass = true;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-fillrule", 1) {
         ARG_CASE("-fillrule", 1) {
             scanlinePass = true;
             scanlinePass = true;
-            if (!strcmp(argv[argPos+1], "nonzero")) fillRule = FILL_NONZERO;
-            else if (!strcmp(argv[argPos+1], "evenodd") || !strcmp(argv[argPos+1], "odd")) fillRule = FILL_ODD;
-            else if (!strcmp(argv[argPos+1], "positive")) fillRule = FILL_POSITIVE;
-            else if (!strcmp(argv[argPos+1], "negative")) fillRule = FILL_NEGATIVE;
+            if (ARG_IS("nonzero")) fillRule = FILL_NONZERO;
+            else if (ARG_IS("evenodd") || ARG_IS("odd")) fillRule = FILL_ODD;
+            else if (ARG_IS("positive")) fillRule = FILL_POSITIVE;
+            else if (ARG_IS("negative")) fillRule = FILL_NEGATIVE;
             else
             else
                 fputs("Unknown fill rule specified.\n", stderr);
                 fputs("Unknown fill rule specified.\n", stderr);
-            argPos += 2;
+            ++argPos;
             continue;
             continue;
         }
         }
         ARG_CASE("-format", 1) {
         ARG_CASE("-format", 1) {
-            if (!strcmp(argv[argPos+1], "auto")) format = AUTO;
+            if (ARG_IS("auto")) format = AUTO;
         #if defined(MSDFGEN_EXTENSIONS) && !defined(MSDFGEN_DISABLE_PNG)
         #if defined(MSDFGEN_EXTENSIONS) && !defined(MSDFGEN_DISABLE_PNG)
-            else if (!strcmp(argv[argPos+1], "png")) SET_FORMAT(PNG, "png");
+            else if (ARG_IS("png")) SET_FORMAT(PNG, "png");
         #else
         #else
-            else if (!strcmp(argv[argPos+1], "png"))
+            else if (ARG_IS("png"))
                 fputs("PNG format is not available in core-only version.\n", stderr);
                 fputs("PNG format is not available in core-only version.\n", stderr);
         #endif
         #endif
-            else if (!strcmp(argv[argPos+1], "bmp")) SET_FORMAT(BMP, "bmp");
-            else if (!strcmp(argv[argPos+1], "tiff") || !strcmp(argv[argPos+1], "tif")) SET_FORMAT(TIFF, "tif");
-            else if (!strcmp(argv[argPos+1], "text") || !strcmp(argv[argPos+1], "txt")) SET_FORMAT(TEXT, "txt");
-            else if (!strcmp(argv[argPos+1], "textfloat") || !strcmp(argv[argPos+1], "txtfloat")) SET_FORMAT(TEXT_FLOAT, "txt");
-            else if (!strcmp(argv[argPos+1], "bin") || !strcmp(argv[argPos+1], "binary")) SET_FORMAT(BINARY, "bin");
-            else if (!strcmp(argv[argPos+1], "binfloat") || !strcmp(argv[argPos+1], "binfloatle")) SET_FORMAT(BINARY_FLOAT, "bin");
-            else if (!strcmp(argv[argPos+1], "binfloatbe")) SET_FORMAT(BINARY_FLOAT_BE, "bin");
+            else if (ARG_IS("bmp")) SET_FORMAT(BMP, "bmp");
+            else if (ARG_IS("tiff") || ARG_IS("tif")) SET_FORMAT(TIFF, "tif");
+            else if (ARG_IS("text") || ARG_IS("txt")) SET_FORMAT(TEXT, "txt");
+            else if (ARG_IS("textfloat") || ARG_IS("txtfloat")) SET_FORMAT(TEXT_FLOAT, "txt");
+            else if (ARG_IS("bin") || ARG_IS("binary")) SET_FORMAT(BINARY, "bin");
+            else if (ARG_IS("binfloat") || ARG_IS("binfloatle")) SET_FORMAT(BINARY_FLOAT, "bin");
+            else if (ARG_IS("binfloatbe")) SET_FORMAT(BINARY_FLOAT_BE, "bin");
             else
             else
                 fputs("Unknown format specified.\n", stderr);
                 fputs("Unknown format specified.\n", stderr);
-            argPos += 2;
+            ++argPos;
             continue;
             continue;
         }
         }
-        ARG_CASE("-size", 2) {
+        ARG_CASE("-dimensions" ARG_CASE_OR "-size", 2) {
             unsigned w, h;
             unsigned w, h;
-            if (!(parseUnsigned(w, argv[argPos+1]) && parseUnsigned(h, argv[argPos+2]) && w && h))
-                ABORT("Invalid size arguments. Use -size <width> <height> with two positive integers.");
+            if (!(parseUnsigned(w, argv[argPos++]) && parseUnsigned(h, argv[argPos++]) && w && h))
+                ABORT("Invalid dimensions. Use -dimensions <width> <height> with two positive integers.");
             width = w, height = h;
             width = w, height = h;
-            argPos += 3;
             continue;
             continue;
         }
         }
         ARG_CASE("-autoframe", 0) {
         ARG_CASE("-autoframe", 0) {
             autoFrame = true;
             autoFrame = true;
-            argPos += 1;
             continue;
             continue;
         }
         }
-        ARG_CASE("-range", 1) {
+        ARG_CASE("-range" ARG_CASE_OR "-unitrange", 1) {
             double r;
             double r;
-            if (!(parseDouble(r, argv[argPos+1]) && r > 0))
+            if (!(parseDouble(r, argv[argPos++]) && r > 0))
                 ABORT("Invalid range argument. Use -range <range> with a positive real number.");
                 ABORT("Invalid range argument. Use -range <range> with a positive real number.");
             rangeMode = RANGE_UNIT;
             rangeMode = RANGE_UNIT;
             range = r;
             range = r;
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-pxrange", 1) {
         ARG_CASE("-pxrange", 1) {
             double r;
             double r;
-            if (!(parseDouble(r, argv[argPos+1]) && r > 0))
+            if (!(parseDouble(r, argv[argPos++]) && r > 0))
                 ABORT("Invalid range argument. Use -pxrange <range> with a positive real number.");
                 ABORT("Invalid range argument. Use -pxrange <range> with a positive real number.");
             rangeMode = RANGE_PX;
             rangeMode = RANGE_PX;
             pxRange = r;
             pxRange = r;
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-scale", 1) {
         ARG_CASE("-scale", 1) {
             double s;
             double s;
-            if (!(parseDouble(s, argv[argPos+1]) && s > 0))
+            if (!(parseDouble(s, argv[argPos++]) && s > 0))
                 ABORT("Invalid scale argument. Use -scale <scale> with a positive real number.");
                 ABORT("Invalid scale argument. Use -scale <scale> with a positive real number.");
             scale = s;
             scale = s;
             scaleSpecified = true;
             scaleSpecified = true;
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-ascale", 2) {
         ARG_CASE("-ascale", 2) {
             double sx, sy;
             double sx, sy;
-            if (!(parseDouble(sx, argv[argPos+1]) && parseDouble(sy, argv[argPos+2]) && sx > 0 && sy > 0))
+            if (!(parseDouble(sx, argv[argPos++]) && parseDouble(sy, argv[argPos++]) && sx > 0 && sy > 0))
                 ABORT("Invalid scale arguments. Use -ascale <x> <y> with two positive real numbers.");
                 ABORT("Invalid scale arguments. Use -ascale <x> <y> with two positive real numbers.");
             scale.set(sx, sy);
             scale.set(sx, sy);
             scaleSpecified = true;
             scaleSpecified = true;
-            argPos += 3;
             continue;
             continue;
         }
         }
         ARG_CASE("-translate", 2) {
         ARG_CASE("-translate", 2) {
             double tx, ty;
             double tx, ty;
-            if (!(parseDouble(tx, argv[argPos+1]) && parseDouble(ty, argv[argPos+2])))
+            if (!(parseDouble(tx, argv[argPos++]) && parseDouble(ty, argv[argPos++])))
                 ABORT("Invalid translate arguments. Use -translate <x> <y> with two real numbers.");
                 ABORT("Invalid translate arguments. Use -translate <x> <y> with two real numbers.");
             translate.set(tx, ty);
             translate.set(tx, ty);
-            argPos += 3;
             continue;
             continue;
         }
         }
         ARG_CASE("-angle", 1) {
         ARG_CASE("-angle", 1) {
             double at;
             double at;
-            if (!parseAngle(at, argv[argPos+1]))
+            if (!parseAngle(at, argv[argPos++]))
                 ABORT("Invalid angle threshold. Use -angle <min angle> with a positive real number less than PI or a value in degrees followed by 'd' below 180d.");
                 ABORT("Invalid angle threshold. Use -angle <min angle> with a positive real number less than PI or a value in degrees followed by 'd' below 180d.");
             angleThreshold = at;
             angleThreshold = at;
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-errorcorrection", 1) {
         ARG_CASE("-errorcorrection", 1) {
-            if (!strcmp(argv[argPos+1], "disabled") || !strcmp(argv[argPos+1], "0") || !strcmp(argv[argPos+1], "none")) {
+            if (ARG_IS("disable") || ARG_IS("disabled") || ARG_IS("0") || ARG_IS("none") || ARG_IS("false")) {
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::DISABLED;
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::DISABLED;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
-            } else if (!strcmp(argv[argPos+1], "default") || !strcmp(argv[argPos+1], "auto") || !strcmp(argv[argPos+1], "auto-mixed") || !strcmp(argv[argPos+1], "mixed")) {
+            } else if (ARG_IS("default") || ARG_IS("auto") || ARG_IS("auto-mixed") || ARG_IS("mixed")) {
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_PRIORITY;
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_PRIORITY;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::CHECK_DISTANCE_AT_EDGE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::CHECK_DISTANCE_AT_EDGE;
-            } else if (!strcmp(argv[argPos+1], "auto-fast") || !strcmp(argv[argPos+1], "fast")) {
+            } else if (ARG_IS("auto-fast") || ARG_IS("fast")) {
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_PRIORITY;
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_PRIORITY;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
-            } else if (!strcmp(argv[argPos+1], "auto-full") || !strcmp(argv[argPos+1], "full")) {
+            } else if (ARG_IS("auto-full") || ARG_IS("full")) {
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_PRIORITY;
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_PRIORITY;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
-            } else if (!strcmp(argv[argPos+1], "distance") || !strcmp(argv[argPos+1], "distance-fast") || !strcmp(argv[argPos+1], "indiscriminate") || !strcmp(argv[argPos+1], "indiscriminate-fast")) {
+            } else if (ARG_IS("distance") || ARG_IS("distance-fast") || ARG_IS("indiscriminate") || ARG_IS("indiscriminate-fast")) {
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::INDISCRIMINATE;
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::INDISCRIMINATE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
-            } else if (!strcmp(argv[argPos+1], "distance-full") || !strcmp(argv[argPos+1], "indiscriminate-full")) {
+            } else if (ARG_IS("distance-full") || ARG_IS("indiscriminate-full")) {
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::INDISCRIMINATE;
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::INDISCRIMINATE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
-            } else if (!strcmp(argv[argPos+1], "edge-fast")) {
+            } else if (ARG_IS("edge-fast")) {
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_ONLY;
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_ONLY;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
-            } else if (!strcmp(argv[argPos+1], "edge") || !strcmp(argv[argPos+1], "edge-full")) {
+            } else if (ARG_IS("edge") || ARG_IS("edge-full")) {
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_ONLY;
                 generatorConfig.errorCorrection.mode = ErrorCorrectionConfig::EDGE_ONLY;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
                 generatorConfig.errorCorrection.distanceCheckMode = ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
-            } else if (!strcmp(argv[argPos+1], "help")) {
+            } else if (ARG_IS("help")) {
                 puts(errorCorrectionHelpText);
                 puts(errorCorrectionHelpText);
                 return 0;
                 return 0;
             } else
             } else
                 fputs("Unknown error correction mode. Use -errorcorrection help for more information.\n", stderr);
                 fputs("Unknown error correction mode. Use -errorcorrection help for more information.\n", stderr);
+            ++argPos;
             explicitErrorCorrectionMode = true;
             explicitErrorCorrectionMode = true;
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-errordeviationratio", 1) {
         ARG_CASE("-errordeviationratio", 1) {
             double edr;
             double edr;
-            if (!(parseDouble(edr, argv[argPos+1]) && edr > 0))
+            if (!(parseDouble(edr, argv[argPos++]) && edr > 0))
                 ABORT("Invalid error deviation ratio. Use -errordeviationratio <ratio> with a positive real number.");
                 ABORT("Invalid error deviation ratio. Use -errordeviationratio <ratio> with a positive real number.");
             generatorConfig.errorCorrection.minDeviationRatio = edr;
             generatorConfig.errorCorrection.minDeviationRatio = edr;
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-errorimproveratio", 1) {
         ARG_CASE("-errorimproveratio", 1) {
             double eir;
             double eir;
-            if (!(parseDouble(eir, argv[argPos+1]) && eir > 0))
+            if (!(parseDouble(eir, argv[argPos++]) && eir > 0))
                 ABORT("Invalid error improvement ratio. Use -errorimproveratio <ratio> with a positive real number.");
                 ABORT("Invalid error improvement ratio. Use -errorimproveratio <ratio> with a positive real number.");
             generatorConfig.errorCorrection.minImproveRatio = eir;
             generatorConfig.errorCorrection.minImproveRatio = eir;
-            argPos += 2;
             continue;
             continue;
         }
         }
-        ARG_CASE("-coloringstrategy", 1) {
-            if (!strcmp(argv[argPos+1], "simple"))
-                edgeColoring = &edgeColoringSimple;
-            else if (!strcmp(argv[argPos+1], "inktrap"))
-                edgeColoring = &edgeColoringInkTrap;
-            else if (!strcmp(argv[argPos+1], "distance"))
-                edgeColoring = &edgeColoringByDistance;
+        ARG_CASE("-coloringstrategy" ARG_CASE_OR "-edgecoloring", 1) {
+            if (ARG_IS("simple")) edgeColoring = &edgeColoringSimple;
+            else if (ARG_IS("inktrap")) edgeColoring = &edgeColoringInkTrap;
+            else if (ARG_IS("distance")) edgeColoring = &edgeColoringByDistance;
             else
             else
                 fputs("Unknown coloring strategy specified.\n", stderr);
                 fputs("Unknown coloring strategy specified.\n", stderr);
-            argPos += 2;
+            ++argPos;
             continue;
             continue;
         }
         }
         ARG_CASE("-edgecolors", 1) {
         ARG_CASE("-edgecolors", 1) {
             static const char *allowed = " ?,cmwyCMWY";
             static const char *allowed = " ?,cmwyCMWY";
-            for (int i = 0; argv[argPos+1][i]; ++i) {
+            for (int i = 0; argv[argPos][i]; ++i) {
                 for (int j = 0; allowed[j]; ++j)
                 for (int j = 0; allowed[j]; ++j)
-                    if (argv[argPos+1][i] == allowed[j])
+                    if (argv[argPos][i] == allowed[j])
                         goto EDGE_COLOR_VERIFIED;
                         goto EDGE_COLOR_VERIFIED;
                 ABORT("Invalid edge coloring sequence. Use -edgecolors <color sequence> with only the colors C, M, Y, and W. Separate contours by commas and use ? to keep the default assigment for a contour.");
                 ABORT("Invalid edge coloring sequence. Use -edgecolors <color sequence> with only the colors C, M, Y, and W. Separate contours by commas and use ? to keep the default assigment for a contour.");
             EDGE_COLOR_VERIFIED:;
             EDGE_COLOR_VERIFIED:;
             }
             }
-            edgeAssignment = argv[argPos+1];
-            argPos += 2;
+            edgeAssignment = argv[argPos++];
             continue;
             continue;
         }
         }
         ARG_CASE("-distanceshift", 1) {
         ARG_CASE("-distanceshift", 1) {
             double ds;
             double ds;
-            if (!parseDouble(ds, argv[argPos+1]))
+            if (!parseDouble(ds, argv[argPos++]))
                 ABORT("Invalid distance shift. Use -distanceshift <shift> with a real value.");
                 ABORT("Invalid distance shift. Use -distanceshift <shift> with a real value.");
             outputDistanceShift = (float) ds;
             outputDistanceShift = (float) ds;
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-exportshape", 1) {
         ARG_CASE("-exportshape", 1) {
-            shapeExport = argv[argPos+1];
-            argPos += 2;
+            shapeExport = argv[argPos++];
             continue;
             continue;
         }
         }
         ARG_CASE("-testrender", 3) {
         ARG_CASE("-testrender", 3) {
             unsigned w, h;
             unsigned w, h;
-            if (!parseUnsigned(w, argv[argPos+2]) || !parseUnsigned(h, argv[argPos+3]) || !w || !h)
+            testRender = argv[argPos++];
+            if (!(parseUnsigned(w, argv[argPos++]) && parseUnsigned(h, argv[argPos++]) && (int) w > 0 && (int) h > 0))
                 ABORT("Invalid arguments for test render. Use -testrender <output." DEFAULT_IMAGE_EXTENSION "> <width> <height>.");
                 ABORT("Invalid arguments for test render. Use -testrender <output." DEFAULT_IMAGE_EXTENSION "> <width> <height>.");
-            testRender = argv[argPos+1];
             testWidth = w, testHeight = h;
             testWidth = w, testHeight = h;
-            argPos += 4;
             continue;
             continue;
         }
         }
         ARG_CASE("-testrendermulti", 3) {
         ARG_CASE("-testrendermulti", 3) {
             unsigned w, h;
             unsigned w, h;
-            if (!parseUnsigned(w, argv[argPos+2]) || !parseUnsigned(h, argv[argPos+3]) || !w || !h)
+            testRenderMulti = argv[argPos++];
+            if (!(parseUnsigned(w, argv[argPos++]) && parseUnsigned(h, argv[argPos++]) && (int) w > 0 && (int) h > 0))
                 ABORT("Invalid arguments for test render. Use -testrendermulti <output." DEFAULT_IMAGE_EXTENSION "> <width> <height>.");
                 ABORT("Invalid arguments for test render. Use -testrendermulti <output." DEFAULT_IMAGE_EXTENSION "> <width> <height>.");
-            testRenderMulti = argv[argPos+1];
             testWidthM = w, testHeightM = h;
             testWidthM = w, testHeightM = h;
-            argPos += 4;
             continue;
             continue;
         }
         }
         ARG_CASE("-yflip", 0) {
         ARG_CASE("-yflip", 0) {
             yFlip = true;
             yFlip = true;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-printmetrics", 0) {
         ARG_CASE("-printmetrics", 0) {
             printMetrics = true;
             printMetrics = true;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-estimateerror", 0) {
         ARG_CASE("-estimateerror", 0) {
             estimateError = true;
             estimateError = true;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-keeporder", 0) {
         ARG_CASE("-keeporder", 0) {
             orientation = KEEP;
             orientation = KEEP;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-reverseorder", 0) {
         ARG_CASE("-reverseorder", 0) {
             orientation = REVERSE;
             orientation = REVERSE;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-guessorder", 0) {
         ARG_CASE("-guessorder", 0) {
             orientation = GUESS;
             orientation = GUESS;
-            argPos += 1;
             continue;
             continue;
         }
         }
         ARG_CASE("-seed", 1) {
         ARG_CASE("-seed", 1) {
-            if (!parseUnsignedLL(coloringSeed, argv[argPos+1]))
+            if (!parseUnsignedLL(coloringSeed, argv[argPos++]))
                 ABORT("Invalid seed. Use -seed <N> with N being a non-negative integer.");
                 ABORT("Invalid seed. Use -seed <N> with N being a non-negative integer.");
-            argPos += 2;
             continue;
             continue;
         }
         }
         ARG_CASE("-version", 0) {
         ARG_CASE("-version", 0) {
@@ -955,9 +917,8 @@ int main(int argc, const char *const *argv) {
             puts(helpText);
             puts(helpText);
             return 0;
             return 0;
         }
         }
-        fprintf(stderr, "Unknown setting or insufficient parameters: %s\n", argv[argPos]);
+        fprintf(stderr, "Unknown setting or insufficient parameters: %s\n", argv[argPos++]);
         suggestHelp = true;
         suggestHelp = true;
-        ++argPos;
     }
     }
     if (suggestHelp)
     if (suggestHelp)
         fprintf(stderr, "Use -help for more information.\n");
         fprintf(stderr, "Use -help for more information.\n");