In avifenc/dec, treat all arguments that start with '-' as flags.
To pass filenames that actually start with '-', users can either
prefix the path with './' or use '--' to signal the end of flags, e.g.
./avifenc --min 0 --max 63 -- --my_input.png output.avif
This creates clearer error messages, e.g.
avifenc input.png output.avif --badflag
would print 'Unrecognized file format: output.avif' but now prints
'ERROR: unrecognized flag --badflag' instead.
diff --git a/apps/avifdec.c b/apps/avifdec.c
index 6617187..27ab40d 100644
--- a/apps/avifdec.c
+++ b/apps/avifdec.c
@@ -47,6 +47,7 @@
printf(" Default: %u, set to a smaller value to further restrict.\n", AVIF_DEFAULT_IMAGE_SIZE_LIMIT);
printf(" --dimension-limit C : Specifies the image dimension limit (width or height) that should be tolerated.\n");
printf(" Default: %u, set to 0 to ignore.\n", AVIF_DEFAULT_IMAGE_DIMENSION_LIMIT);
+ printf(" -- : Signals the end of options. Everything after this is interpreted as file names.\n");
printf("\n");
avifPrintVersions();
}
@@ -79,7 +80,25 @@
while (argIndex < argc) {
const char * arg = argv[argIndex];
- if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) {
+ if (!strcmp(arg, "--")) {
+ // Stop parsing flags, everything after this is positional arguments
+ ++argIndex;
+ // Parse additional positional arguments if any.
+ while (argIndex < argc) {
+ arg = argv[argIndex];
+ if (!inputFilename) {
+ inputFilename = arg;
+ } else if (!outputFilename) {
+ outputFilename = arg;
+ } else {
+ fprintf(stderr, "Too many positional arguments: %s\n\n", arg);
+ syntax();
+ return 1;
+ }
+ ++argIndex;
+ }
+ break;
+ } else if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) {
syntax();
return 0;
} else if (!strcmp(arg, "-V") || !strcmp(arg, "--version")) {
@@ -176,6 +195,10 @@
return 1;
}
imageDimensionLimit = (uint32_t)value;
+ } else if (arg[0] == '-') {
+ fprintf(stderr, "ERROR: unrecognized option %s\n\n", arg);
+ syntax();
+ return 1;
} else {
// Positional argument
if (!inputFilename) {
@@ -183,7 +206,7 @@
} else if (!outputFilename) {
outputFilename = arg;
} else {
- fprintf(stderr, "Too many positional arguments: %s\n", arg);
+ fprintf(stderr, "Too many positional arguments: %s\n\n", arg);
syntax();
return 1;
}
diff --git a/apps/avifenc.c b/apps/avifenc.c
index 1e7c3d6..485b350 100644
--- a/apps/avifenc.c
+++ b/apps/avifenc.c
@@ -104,6 +104,7 @@
printf(" --clap WN,WD,HN,HD,HON,HOD,VON,VOD: Add clap property (clean aperture). Width, Height, HOffset, VOffset (in num/denom pairs)\n");
printf(" --irot ANGLE : Add irot property (rotation). [0-3], makes (90 * ANGLE) degree rotation anti-clockwise\n");
printf(" --imir MODE : Add imir property (mirroring). 0=top-to-bottom, 1=left-to-right\n");
+ printf(" -- : Signals the end of options. Everything after this is interpreted as file names.\n");
printf("\n");
if (avifCodecName(AVIF_CODEC_CHOICE_AOM, 0)) {
printf("aom-specific advanced options:\n");
@@ -470,7 +471,19 @@
while (argIndex < argc) {
const char * arg = argv[argIndex];
- if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) {
+ if (!strcmp(arg, "--")) {
+ // Stop parsing flags, everything after this is positional arguments
+ ++argIndex;
+ // Parse additional positional arguments if any
+ while (argIndex < argc) {
+ arg = argv[argIndex];
+ input.files[input.filesCount].filename = arg;
+ input.files[input.filesCount].duration = outputTiming.duration;
+ ++input.filesCount;
+ ++argIndex;
+ }
+ break;
+ } else if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) {
syntax();
goto cleanup;
} else if (!strcmp(arg, "-V") || !strcmp(arg, "--version")) {
@@ -747,6 +760,11 @@
matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY; // this is key for lossless
} else if (!strcmp(arg, "-p") || !strcmp(arg, "--premultiply")) {
premultiplyAlpha = AVIF_TRUE;
+ } else if (arg[0] == '-') {
+ fprintf(stderr, "ERROR: unrecognized option %s\n\n", arg);
+ syntax();
+ returnCode = 1;
+ goto cleanup;
} else {
// Positional argument
input.files[input.filesCount].filename = arg;
diff --git a/apps/shared/avifutil.c b/apps/shared/avifutil.c
index f6657a1..01c8ec9 100644
--- a/apps/shared/avifutil.c
+++ b/apps/shared/avifutil.c
@@ -252,7 +252,7 @@
return AVIF_APP_FILE_FORMAT_UNKNOWN;
}
} else {
- fprintf(stderr, "Unrecognized file format: %s\n", filename);
+ fprintf(stderr, "Unrecognized file format for input file: %s\n", filename);
return AVIF_APP_FILE_FORMAT_UNKNOWN;
}
return format;
diff --git a/doc/avifdec.1.md b/doc/avifdec.1.md
index 06b25b5..05d0044 100644
--- a/doc/avifdec.1.md
+++ b/doc/avifdec.1.md
@@ -117,6 +117,9 @@
tolerated.
Default is 32,768. Set it to 0 to ignore the limit.
+**\--**
+: Signals the end of options. Everything after this is interpreted as file names.
+
# EXAMPLES
Decompress an AVIF file to a PNG file:
diff --git a/doc/avifenc.1.md b/doc/avifenc.1.md
index 7196278..a99cf1a 100644
--- a/doc/avifenc.1.md
+++ b/doc/avifenc.1.md
@@ -226,6 +226,9 @@
: - **0** (top-to-bottom)
- **1** (left-to-right)
+**\--**
+: Signals the end of options. Everything after this is interpreted as file names.
+
# EXAMPLES
Compress a PNG file to an AVIF file:
diff --git a/tests/test_cmd.sh b/tests/test_cmd.sh
index 3803cd7..c280c0f 100755
--- a/tests/test_cmd.sh
+++ b/tests/test_cmd.sh
@@ -37,6 +37,7 @@
TMP_ENCODED_FILE=/tmp/encoded.avif
DECODED_FILE=/tmp/decoded.png
PNG_FILE=/tmp/kodim03.png
+TMP_ENCODED_FILE_WTH_DASH=-encoded.avif
# Prepare some extra data.
set +x
@@ -55,6 +56,24 @@
"${AVIFDEC}" "${TMP_ENCODED_FILE}" "${DECODED_FILE}"
"${ARE_IMAGES_EQUAL}" "${PNG_FILE}" "${DECODED_FILE}" 0
+# Argument parsing test with filenames starting with a dash.
+"${AVIFENC}" -s 10 "${PNG_FILE}" -- "${TMP_ENCODED_FILE_WTH_DASH}"
+"${AVIFDEC}" --info -- "${TMP_ENCODED_FILE_WTH_DASH}"
+# Passing a filename starting with a dash without using -- should fail.
+set +e
+"${AVIFENC}" -s 10 "${PNG_FILE}" "${TMP_ENCODED_FILE_WTH_DASH}"
+if [[ $? -ne 1 ]]; then
+ echo "Argument parsing should fail for avifenc"
+ exit 1
+fi
+"${AVIFDEC}" --info "${TMP_ENCODED_FILE_WTH_DASH}"
+if [[ $? -ne 1 ]]; then
+ echo "Argument parsing should fail for avifdec"
+ exit 1
+fi
+set -e
+rm -- "${TMP_ENCODED_FILE_WTH_DASH}"
+
# Test code that should fail.
set +e
"${ARE_IMAGES_EQUAL}" "${TESTDATA_DIR}"/kodim23_yuv420_8bpc.y4m "${DECODED_FILE}" 0