Files
kaguya 9a9b91c940 user: implement mlibc as the libc, finally.
It's finally done..

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
2026-05-02 03:31:49 -04:00

885 lines
18 KiB
C

#include <assert.h>
#include <getopt.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define dump(x) fprintf(stderr, "getopt c '%c' (%d), optind %d ('%s'), optarg '%s', optopt '%c' (%d)\n", \
(x), (x), optind, (size_t)optind >= COUNT_OF(test_argv) ? "out of range" : test_argv[optind], optarg, optopt, optopt);
#define dumpargv(argv) do { \
fprintf(stderr, "args(%zu) {\n", COUNT_OF(argv)); \
for (size_t i = 0; i < COUNT_OF(argv); i++) { \
fprintf(stderr, "\targv[%zu] = '%s'\n", i, argv[i]); \
} \
fprintf(stderr, "}\n"); \
} while (0)
void test1() {
const char *shortopts = "b:cdef";
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
int test_argc = 7;
char *test_argv[] = {
"dummy",
"--foo",
"abc",
"-b",
"abc",
"abc",
"abc"
};
optind = 0;
int c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL);
dump(c)
assert(c == 'f');
c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL);
dump(c)
assert(optarg && !strcmp(optarg, "abc"));
assert(c == 'b');
c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL);
dump(c);
assert(c == -1);
assert(optarg == NULL);
// we have 2 non-option arguments
assert((optind + 2) == test_argc);
}
void test2() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-c",
};
fputs("Situation: we pass a non-existant short option in argv\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:", longopts, NULL);
// Expected result: return '?', optopt is set to the offender
assert(c == '?');
assert(optopt == 'c');
fputs("Situation: we pass a non-existant short option in argv, while passing a leading colon in optstring\n", stderr);
optind = 0;
c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:", longopts, NULL);
// Expected result: return '?', optopt is set to the offender
assert(c == '?');
assert(optopt == 'c');
fputs("Situation: we omit the required arg to a short option\n", stderr);
optind = 0;
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL);
// Expected result: return '?', optopt is set to the offender
assert(c == '?');
assert(optopt == 'c');
fputs("Situation: we omit the required arg to a short option, while passing a leading colon in optstring\n", stderr);
optind = 0;
c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:c:", longopts, NULL);
// Expected result: return ':', optopt is set to the offender
assert(c == ':');
assert(optopt == 'c');
}
void test3() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-cmanagarm",
};
fputs("Situation: we pass a concatenated argument to a short option\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL);
dump(c);
// Expected result:
assert(c == 'c');
assert(!strcmp(optarg, "managarm"));
}
void test4() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-acmanagarm",
};
fputs("Situation: we pass concatenated short options to getopt\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL);
assert(c == 'a');
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL);
// Expected result:
assert(c == 'c');
assert(!strcmp(optarg, "managarm"));
}
void test5() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, no_argument, NULL, 0}
};
char *test_argv[] = {
"su",
"-",
"managarm",
0
};
int test_argc = 3;
fputs("Situation: testing `su - managarm`\n", stderr);
optind = 0;
int c = getopt_long(test_argc, test_argv, "ab:", longopts, NULL);
dump(c);
assert(c == -1);
if (optind < test_argc && !strcmp(test_argv[optind], "-")) {
++optind;
}
assert(optind < test_argc);
assert(!strcmp(test_argv[optind++], "managarm"));
assert(optind == test_argc);
}
void test6() {
char *test_argv[] = {
"telescope",
"gemini://electrode.codes",
"-S",
0
};
int test_argc = 3;
optind = 0;
const struct option longopts[] = {
{"colors", no_argument, NULL, 'C'},
{"colours", no_argument, NULL, 'C'},
{"help", no_argument, NULL, 'h'},
{"safe", no_argument, NULL, 'S'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0},
};
int c = getopt_long(test_argc, test_argv, "Cc:hnST:v", longopts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == 'S');
c = getopt_long(test_argc, test_argv, "Cc:hnST:v", longopts, NULL);
dump(c);
dumpargv(test_argv);
assert(optind == 2);
assert(!optarg);
}
void test7() {
int c;
static const struct option options[] = {
{ "debug", no_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{}
};
const char *command;
char *test_argv[] = {
"udevadm",
"hwdb",
"--update",
0
};
int test_argc = 3;
setenv("POSIXLY_CORRECT", "1", 1);
optind = 0;
while ((c = getopt_long(test_argc, test_argv, "+dhV", options, NULL)) >= 0) {
switch (c) {
case 'd':
break;
case 'h':
break;
case 'V':
break;
default:
break;
}
}
dump(c);
command = test_argv[optind];
assert(command);
assert(!strcmp(command, "hwdb"));
unsetenv("POSIXLY_CORRECT");
}
void test8() {
const char *shortopts = "b:cde";
int foo = false;
int bar = false;
const struct option longopts[] = {
{"foo", required_argument, &foo, 'x'},
{"bar", required_argument, &bar, 'y'},
{NULL, no_argument, NULL, 0}
};
int test_argc = 6;
char *test_argv[] = {
"dummy",
"-foo",
"abc",
"-bar=def",
"ghi",
"jkl"
};
#ifdef __GLIBC__
optind = 0;
#else
optreset = 1;
#endif
optopt = 0;
int c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL);
dump(c);
assert(foo && !c);
assert(optind == 3);
c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL);
dump(c);
assert(bar && !c);
assert(optind == 4);
}
void test9() {
char *test_argv[] = {
"foo",
};
struct option opts[] = { {0} };
optind = 0;
int c = getopt_long(1, test_argv, "abc", opts, NULL);
dump(c);
assert(c == -1);
}
void test10() {
char *test_argv[] = {
"foo",
"nonoption",
"-a",
"nonoption2",
"nonoption3",
"-b",
"-c",
};
struct option opts[] = { {0} };
optind = 2;
dump(0);
int c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == 'a');
c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == 'b');
c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == 'c');
c = getopt_long(COUNT_OF(test_argv), test_argv, "abc", opts, NULL);
dump(c);
dumpargv(test_argv);
assert(c == -1);
assert(!strcmp(test_argv[0], "foo"));
assert(!strcmp(test_argv[1], "nonoption"));
assert(!strcmp(test_argv[2], "-a"));
assert(!strcmp(test_argv[3], "-b"));
assert(!strcmp(test_argv[4], "-c"));
assert(!strcmp(test_argv[5], "nonoption2"));
assert(!strcmp(test_argv[6], "nonoption3"));
}
void test11() {
const struct option longopts[] = {
{"op", optional_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"--op",
"--op=arg",
"non-option",
"--op"
};
fputs("Situation: optional argument to long option\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'o');
assert(optarg == NULL);
c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'o');
assert(!strcmp(optarg, "arg"));
c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'o');
assert(optarg == NULL);
}
void test12() {
char *test_argv[] = {
"dummy",
"-a",
"-b",
"arg",
"-carg",
"arg",
};
fputs("Situation: optional argument to short option\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL);
assert(c == 'a');
assert(optarg == NULL);
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL);
assert(c == 'b');
assert(!optarg);
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL);
assert(c == 'c');
assert(!strcmp(optarg, "arg"));
c = getopt_long(COUNT_OF(test_argv), test_argv, "ab::c::", NULL, NULL);
assert(c == -1);
assert(optind == 4);
assert(!strcmp(test_argv[optind], "arg"));
}
void test13() {
const struct option longopts[] = {
{"ambiguous-opt", no_argument, NULL, 0},
{"ambiguous-option", no_argument, NULL, 1},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"--ambiguous-o"
};
fputs("Situation: ambiguous long option\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == '?');
}
void test14() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-Wfoo=bar",
};
fputs("Situation: -W for long options\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == 'f');
assert(!strcmp(optarg, "bar"));
}
void test15() {
char *test_argv[] = {
"dummy",
"-c",
"-a",
"--",
"-b"
};
fputs("Situation: -- to stop option processing\n", stderr);
optind = 0;
int c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == '?');
assert(optind == 2);
c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == 'a');
assert(optind == 3);
c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == -1);
assert(optind == 4);
assert(!strcmp(test_argv[optind], "-b"));
}
void test16() {
const struct option longopts[] = {
{"add", required_argument, NULL, 'a'},
{"append", no_argument, NULL, 'p'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"--ad=foo",
"--appe"
};
fputs("Situation: non-ambiguous long option prefix\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'a');
assert(!strcmp(optarg, "foo"));
c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'p');
assert(optarg == NULL);
}
void test17() {
const struct option longopts[] = {
{"foo", no_argument, NULL, 'l'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-foo"
};
fputs("Situation: getopt_long_only with what could be short opts or a long opt\n", stderr);
// Case 1: long option "foo" exists, so "-foo" should be treated as "--foo"
optind = 0;
int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "f:o", longopts, NULL);
assert(c == 'l');
// Case 2: long option "foo" does not exist.
const struct option longopts2[] = {
{"bar", no_argument, NULL, 'b'},
{NULL, 0, NULL, 0}
};
optind = 0;
c = getopt_long_only(COUNT_OF(test_argv), test_argv, "f:o", longopts2, NULL);
assert(c == 'f');
assert(!strcmp(optarg, "oo"));
}
void test18() {
const struct option longopts[] = {
{"op", optional_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-Wop=val",
};
fputs("Situation: -W with a long option with an optional argument (with value)\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == 'o');
assert(!strcmp(optarg, "val"));
char *test_argv2[] = {
"dummy",
"-Wop",
};
fputs("Situation: -W with a long option with an optional argument (no value)\n", stderr);
optind = 0;
c = getopt_long(COUNT_OF(test_argv2), test_argv2, "W;", longopts, NULL);
assert(c == 'o');
assert(optarg == NULL);
}
void test19() {
char *test_argv[] = {
"dummy",
"-a",
"non-option",
"-b",
};
fputs("Situation: POSIXLY_CORRECT behavior with '+'\n", stderr);
optind = 0;
int c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == 'a');
c = getopt(COUNT_OF(test_argv), test_argv, "+ab");
assert(c == -1);
assert(optind == 2);
assert(!strcmp(test_argv[optind], "non-option"));
}
void test20() {
const struct option longopts[] = {
{"option", required_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"--option",
"-x",
};
fputs("Situation: long option with argument that looks like an option\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "x", longopts, NULL);
assert(c == 'o');
assert(!strcmp(optarg, "-x"));
assert(optind == 3);
}
void test21() {
const struct option longopts[] = {
{"ambig-one", no_argument, NULL, '1'},
{"ambig-two", no_argument, NULL, '2'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-ambig",
};
fputs("Situation: ambiguous long option with getopt_long_only\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == '?');
}
void test22() {
const struct option longopts[] = {
{"foo", no_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-Wbar",
};
fputs("Situation: -W with non-existent long option\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == '?');
assert(optind == 2);
}
void test23() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-foo",
"val1",
"-foo=val2",
};
fputs("Situation: getopt_long_only with required argument\n", stderr);
optind = 0;
int c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'f');
assert(!strcmp(optarg, "val1"));
assert(optind == 3);
c = getopt_long_only(COUNT_OF(test_argv), test_argv, "", longopts, NULL);
assert(c == 'f');
assert(!strcmp(optarg, "val2"));
assert(optind == 4);
}
void test24() {
char *test_argv[] = {
"dummy",
"-W",
};
fputs("Situation: -W as a short option, not for passing long options\n", stderr);
optind = 0;
int c = getopt(COUNT_OF(test_argv), test_argv, "W");
assert(c == 'W');
assert(optind == 2);
}
void test25() {
const struct option longopts[] = {
{"foo", required_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-Wfoo",
};
fputs("Situation: -W with missing argument for a long option, with ':' in optstring\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, ":W;", longopts, NULL);
assert(c == ':');
assert(optopt == 'f');
assert(optind == 2);
}
void test26() {
const struct option longopts[] = {
{"foo", no_argument, NULL, 0},
{"ambig-one", no_argument, NULL, 1},
{"ambig-two", no_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"dummy",
"-W",
};
fputs("Situation: -W without an argument\n", stderr);
optind = 0;
opterr = 1;
int c = getopt_long(COUNT_OF(test_argv), test_argv, ":W;", longopts, NULL);
assert(c == ':');
assert(optopt == 'W');
assert(optind == 2);
}
void test27() {
char *test_argv[] = {
"dummy",
"-Wambig",
};
const struct option longopts[] = {
{"foo", no_argument, NULL, 0},
{"ambig-one", no_argument, NULL, 1},
{"ambig-two", no_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
fputs("Situation: -W with an ambiguous long option\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == '?');
assert(optind == 2);
}
void test28() {
char *test_argv[] = {
"dummy",
"-Wfoo=bar",
"-Wfoo=",
};
const struct option longopts[] = {
{"foo", no_argument, NULL, 0},
{"ambig-one", no_argument, NULL, 1},
{"ambig-two", no_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
fputs("Situation: -W with an argument to a long option that does not take one\n", stderr);
optind = 0;
opterr = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == '?');
assert(optind == 2);
c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == '?');
assert(optind == 3);
c = getopt_long(COUNT_OF(test_argv), test_argv, "W;", longopts, NULL);
assert(c == -1);
}
void test29() {
char *test_argv[] = {
"dummy",
"--a",
};
const struct option longopts[] = {
{"load-credentials", no_argument, NULL, 0x103},
{NULL, 0, NULL, 0},
};
optind = 0;
opterr = 1;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "el:sSRp:m:t:Vh", longopts, NULL);
dump(c);
assert(c == '?');
assert(optind == 2);
}
void test30() {
const struct option longopts[] = {
{"long-opt", required_argument, NULL, 'l'},
{NULL, 0, NULL, 0}
};
char *test_argv[] = {
"getopt_test",
"non-arg1",
"--long-opt",
"val",
"non-arg2"
};
fputs("Situation: non-arguments before valid long arguments\n", stderr);
optind = 0;
int c = getopt_long(COUNT_OF(test_argv), test_argv, "+", longopts, NULL);
assert(c == -1);
assert(optind == 1);
assert(!strcmp(test_argv[0], "getopt_test"));
assert(!strcmp(test_argv[1], "non-arg1"));
assert(!strcmp(test_argv[2], "--long-opt"));
assert(!strcmp(test_argv[3], "val"));
assert(!strcmp(test_argv[4], "non-arg2"));
optind = 2;
while ((c = getopt_long(COUNT_OF(test_argv), test_argv, "+", longopts, NULL)) != -1) {
switch (c) {
case 'l':
assert(!strcmp(optarg, "val"));
break;
default:
break;
}
}
assert(c == -1);
assert(optind == 4);
optind = 0;
while ((c = getopt_long(COUNT_OF(test_argv), test_argv, "", longopts, NULL)) != -1) {
switch (c) {
case 'l':
assert(!strcmp(optarg, "val"));
break;
default:
break;
}
}
assert(optind == 3);
assert(!strcmp(test_argv[0], "getopt_test"));
assert(!strcmp(test_argv[1], "--long-opt"));
assert(!strcmp(test_argv[2], "val"));
assert(!strcmp(test_argv[3], "non-arg1"));
assert(!strcmp(test_argv[4], "non-arg2"));
}
int main() {
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
test10();
test11();
test12();
test13();
test14();
test15();
test16();
test17();
test18();
test19();
test20();
test21();
test22();
test23();
test24();
test25();
test26();
test27();
test28();
test29();
test30();
return 0;
}