endif
$(o)/ucw/ipaccess-test: $(o)/ucw/ipaccess-test.o $(LIBUCW)
$(o)/ucw/trie-test: $(o)/ucw/trie-test.o $(LIBUCW)
+$(o)/ucw/opt-test: $(o)/ucw/opt-test.o $(LIBUCW)
TESTS+=$(addprefix $(o)/ucw/,regex.test unicode.test hash-test.test mempool.test stkstring.test \
slists.test bbuf.test kmp-test.test getopt.test ff-unicode.test eltpool.test \
$(o)/ucw/crc.test: $(o)/ucw/crc-t
$(o)/ucw/signames.test: $(o)/ucw/signames-t
$(o)/ucw/md5.test: $(o)/ucw/md5-t
-$(o)/ucw/opt.test: $(o)/ucw/opt-t
+$(o)/ucw/opt.test: $(o)/ucw/opt-test
ifdef CONFIG_UCW_THREADS
TESTS+=$(addprefix $(o)/ucw/,asio.test)
--- /dev/null
+/*
+ * UCW Library -- Parsing of command line options
+ *
+ * (c) 2013 Jan Moskyto Matejka <mq@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#include <ucw/lib.h>
+#include <ucw/opt.h>
+#include <ucw/strtonum.h>
+#include <ucw/fastbuf.h>
+
+static void show_version(struct opt_item * opt UNUSED, const char * value UNUSED, void * data UNUSED) {
+ printf("This is a simple tea boiling console v0.1.\n");
+ exit(EXIT_SUCCESS);
+}
+
+struct teapot_temperature {
+ enum {
+ TEMP_CELSIUS = 0,
+ TEMP_FAHRENHEIT,
+ TEMP_KELVIN,
+ TEMP_REAUMUR,
+ TEMP_RANKINE
+ } scale;
+ int value;
+} temperature;
+
+static char * temp_scale_str[] = { "C", "F", "K", "Re", "R" };
+
+static enum TEAPOT_TYPE {
+ TEAPOT_STANDARD = 0,
+ TEAPOT_EXCLUSIVE,
+ TEAPOT_GLASS,
+ TEAPOT_HANDS,
+ TEAPOT_UNDEFINED = -1
+} set = TEAPOT_UNDEFINED;
+
+static char * teapot_type_str[] = { "standard", "exclusive", "glass", "hands" };
+
+static int show_hooks = 0;
+static int english = 0;
+static int sugar = 0;
+static int verbose = 1;
+static int with_gas = 0;
+static clist black_magic;
+static int pray = 0;
+static int water_amount = 0;
+static char * first_tea = NULL;
+
+#define MAX_TEA_COUNT 30
+static char * tea_list[MAX_TEA_COUNT];
+static int tea_num = 0;
+static void add_tea(struct opt_item * opt UNUSED, const char * name, void * data) {
+ char ** tea_list = data;
+ if (tea_num >= MAX_TEA_COUNT) {
+ fprintf(stderr, "Cannot boil more than %d teas.\n", MAX_TEA_COUNT);
+ exit(OPT_EXIT_BAD_ARGS);
+ }
+ tea_list[tea_num++] = xstrdup(name);
+}
+
+static const char * teapot_temperature_parser(char * in, void * ptr) {
+ struct teapot_temperature * temp = ptr;
+ const char * next;
+ const char * err = str_to_int(&temp->value, in, &next, 10);
+ if (err)
+ return err;
+ if (!strcmp("C", next))
+ temp->scale = TEMP_CELSIUS;
+ else if (!strcmp("F", next))
+ temp->scale = TEMP_FAHRENHEIT;
+ else if (!strcmp("K", next))
+ temp->scale = TEMP_KELVIN;
+ else if (!strcmp("R", next))
+ temp->scale = TEMP_RANKINE;
+ else if (!strcmp("Re", next))
+ temp->scale = TEMP_REAUMUR;
+ else {
+ fprintf(stderr, "Unknown scale: %s\n", next);
+ exit(OPT_EXIT_BAD_ARGS);
+ }
+ return NULL;
+}
+
+static void teapot_temperature_dumper(struct fastbuf * fb, void * ptr) {
+ struct teapot_temperature * temp = ptr;
+ bprintf(fb, "%d%s", temp->value, temp_scale_str[temp->scale]);
+}
+
+static struct cf_user_type teapot_temperature_t = {
+ .size = sizeof(struct teapot_temperature),
+ .name = "teapot_temperature_t",
+ .parser = (cf_parser1*) teapot_temperature_parser,
+ .dumper = (cf_dumper1*) teapot_temperature_dumper
+};
+
+static void opt_test_hook(struct opt_item * opt, const char * value, void * data) {
+ if (!show_hooks)
+ return;
+ if (opt)
+ printf("[HOOK-%s:%c/%s=%s] ", (char *) data, opt->letter, opt->name, value);
+ else
+ printf("[HOOK-%s] ", (char *) data);
+}
+
+static struct opt_section water_options = {
+ OPT_ITEMS {
+ OPT_INT('w', "water", water_amount, OPT_REQUIRED | OPT_REQUIRED_VALUE, "<volume>\tAmount of water (in mls; required)"),
+ OPT_BOOL('G', "with-gas", with_gas, OPT_NO_VALUE, "\tUse water with gas"),
+ OPT_END
+ }
+};
+
+static struct opt_section help = {
+ OPT_ITEMS {
+ OPT_HELP("A simple tea boiling console."),
+ OPT_HELP("Usage: teapot [options] name-of-the-tea"),
+ OPT_HELP("Black, green or white tea supported as well as fruit or herbal tea."),
+ OPT_HELP("You may specify more kinds of tea, all of them will be boiled for you, in the given order."),
+ OPT_HELP("At least one kind of tea must be specified."),
+ OPT_HELP(""),
+ OPT_HELP("Options:"),
+ OPT_HELP_OPTION,
+ OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
+ OPT_HELP(""),
+ OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
+ OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
+ OPT_SWITCH(0, "standard-set", set, TEAPOT_STANDARD, 0, "\tStandard teapot"),
+ OPT_SWITCH('x', "exclusive-set", set, TEAPOT_EXCLUSIVE, 0, "\tExclusive teapot"),
+ OPT_SWITCH('g', "glass-set", set, TEAPOT_GLASS, 0, "\tTransparent glass teapot"),
+ OPT_SWITCH('h', "hands", set, TEAPOT_HANDS, 0, "\tUse user's hands as a teapot (a bit dangerous)"),
+ OPT_USER('t', "temperature", temperature, teapot_temperature_t, OPT_REQUIRED_VALUE | OPT_REQUIRED,
+ "<value>\tWanted final temperature of the tea to be served (required)\n"
+ "\t\tSupported scales: Celsius [60C], Fahrenheit [140F],\n"
+ "\t\t Kelvin [350K], Rankine [600R] and Reaumur [50Re]\n"
+ "\t\tOnly integer values allowed."),
+ OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
+ OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"),
+ OPT_INT('b', "black-magic", black_magic, OPT_MULTIPLE, "<strength>\tUse black magic to make the tea extraordinary delicious.\n\t\tMay be specified more than once to describe the amounts of black magic to be invoked in each step of tea boiling."),
+ OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"),
+ OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED | OPT_NO_HELP, ""),
+ OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, OPT_NO_HELP, ""),
+ OPT_HELP(""),
+ OPT_HELP("Water options:"),
+ OPT_SECTION(water_options),
+ OPT_HOOK(opt_test_hook, "prearg", OPT_HOOK_BEFORE_ARG),
+ OPT_HOOK(opt_test_hook, "preval", OPT_HOOK_BEFORE_VALUE),
+ OPT_HOOK(opt_test_hook, "postval", OPT_HOOK_AFTER_VALUE),
+ OPT_BOOL('H', "show-hooks", show_hooks, 0, "Demonstrate the hooks."),
+ OPT_CONF_OPTIONS,
+ OPT_END
+ }
+};
+
+struct intnode {
+ cnode n;
+ int x;
+};
+
+int main(int argc UNUSED, char ** argv)
+{
+ clist_init(&black_magic);
+ opt_parse(&help, argv+1);
+
+ printf("English style: %s|", english ? "yes" : "no");
+ if (sugar)
+ printf("Sugar: %d teaspoons|", sugar);
+ if (set != -1)
+ printf("Chosen teapot: %s|", teapot_type_str[set]);
+ printf("Temperature: %d%s|", temperature.value, temp_scale_str[temperature.scale]);
+ printf("Verbosity: %d|", verbose);
+ CLIST_FOR_EACH(struct intnode *, n, black_magic)
+ printf("Black magic: %d|", n->x);
+ printf("Prayer: %s|", pray ? "yes" : "no");
+ printf("Water amount: %d|", water_amount);
+ printf("Gas: %s|", with_gas ? "yes" : "no");
+ printf("First tea: %s|", first_tea);
+ for (int i=0; i<tea_num; i++)
+ printf("Boiling a tea: %s|", tea_list[i]);
+
+ printf("Everything OK. Bye.\n");
+}
ASSERT(0);
}
}
-
-#ifdef TEST
-#include <ucw/fastbuf.h>
-
-static void show_version(struct opt_item * opt UNUSED, const char * value UNUSED, void * data UNUSED) {
- printf("This is a simple tea boiling console v0.1.\n");
- exit(EXIT_SUCCESS);
-}
-
-struct teapot_temperature {
- enum {
- TEMP_CELSIUS = 0,
- TEMP_FAHRENHEIT,
- TEMP_KELVIN,
- TEMP_REAUMUR,
- TEMP_RANKINE
- } scale;
- int value;
-} temperature;
-
-static char * temp_scale_str[] = { "C", "F", "K", "Re", "R" };
-
-static enum TEAPOT_TYPE {
- TEAPOT_STANDARD = 0,
- TEAPOT_EXCLUSIVE,
- TEAPOT_GLASS,
- TEAPOT_HANDS,
- TEAPOT_UNDEFINED = -1
-} set = TEAPOT_UNDEFINED;
-
-static char * teapot_type_str[] = { "standard", "exclusive", "glass", "hands" };
-
-static int show_hooks = 0;
-static int english = 0;
-static int sugar = 0;
-static int verbose = 1;
-static int with_gas = 0;
-static clist black_magic;
-static int pray = 0;
-static int water_amount = 0;
-static char * first_tea = NULL;
-
-#define MAX_TEA_COUNT 30
-static char * tea_list[MAX_TEA_COUNT];
-static int tea_num = 0;
-static void add_tea(struct opt_item * opt UNUSED, const char * name, void * data) {
- char ** tea_list = data;
- if (tea_num >= MAX_TEA_COUNT) {
- fprintf(stderr, "Cannot boil more than %d teas.\n", MAX_TEA_COUNT);
- exit(OPT_EXIT_BAD_ARGS);
- }
- tea_list[tea_num++] = xstrdup(name);
-}
-
-static const char * teapot_temperature_parser(char * in, void * ptr) {
- struct teapot_temperature * temp = ptr;
- const char * next;
- const char * err = str_to_int(&temp->value, in, &next, 10);
- if (err)
- return err;
- if (!strcmp("C", next))
- temp->scale = TEMP_CELSIUS;
- else if (!strcmp("F", next))
- temp->scale = TEMP_FAHRENHEIT;
- else if (!strcmp("K", next))
- temp->scale = TEMP_KELVIN;
- else if (!strcmp("R", next))
- temp->scale = TEMP_RANKINE;
- else if (!strcmp("Re", next))
- temp->scale = TEMP_REAUMUR;
- else {
- fprintf(stderr, "Unknown scale: %s\n", next);
- exit(OPT_EXIT_BAD_ARGS);
- }
- return NULL;
-}
-
-static void teapot_temperature_dumper(struct fastbuf * fb, void * ptr) {
- struct teapot_temperature * temp = ptr;
- bprintf(fb, "%d%s", temp->value, temp_scale_str[temp->scale]);
-}
-
-static struct cf_user_type teapot_temperature_t = {
- .size = sizeof(struct teapot_temperature),
- .name = "teapot_temperature_t",
- .parser = (cf_parser1*) teapot_temperature_parser,
- .dumper = (cf_dumper1*) teapot_temperature_dumper
-};
-
-static void opt_test_hook(struct opt_item * opt, const char * value, void * data) {
- if (!show_hooks)
- return;
- if (opt)
- printf("[HOOK-%s:%c/%s=%s] ", (char *) data, opt->letter, opt->name, value);
- else
- printf("[HOOK-%s] ", (char *) data);
-}
-
-static struct opt_section water_options = {
- OPT_ITEMS {
- OPT_INT('w', "water", water_amount, OPT_REQUIRED | OPT_REQUIRED_VALUE, "<volume>\tAmount of water (in mls; required)"),
- OPT_BOOL('G', "with-gas", with_gas, OPT_NO_VALUE, "\tUse water with gas"),
- OPT_END
- }
-};
-
-static struct opt_section help = {
- OPT_ITEMS {
- OPT_HELP("A simple tea boiling console."),
- OPT_HELP("Usage: teapot [options] name-of-the-tea"),
- OPT_HELP("Black, green or white tea supported as well as fruit or herbal tea."),
- OPT_HELP("You may specify more kinds of tea, all of them will be boiled for you, in the given order."),
- OPT_HELP("At least one kind of tea must be specified."),
- OPT_HELP(""),
- OPT_HELP("Options:"),
- OPT_HELP_OPTION,
- OPT_CALL('V', "version", show_version, NULL, OPT_NO_VALUE, "\tShow the version"),
- OPT_HELP(""),
- OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
- OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
- OPT_SWITCH(0, "standard-set", set, TEAPOT_STANDARD, 0, "\tStandard teapot"),
- OPT_SWITCH('x', "exclusive-set", set, TEAPOT_EXCLUSIVE, 0, "\tExclusive teapot"),
- OPT_SWITCH('g', "glass-set", set, TEAPOT_GLASS, 0, "\tTransparent glass teapot"),
- OPT_SWITCH('h', "hands", set, TEAPOT_HANDS, 0, "\tUse user's hands as a teapot (a bit dangerous)"),
- OPT_USER('t', "temperature", temperature, teapot_temperature_t, OPT_REQUIRED_VALUE | OPT_REQUIRED,
- "<value>\tWanted final temperature of the tea to be served (required)\n"
- "\t\tSupported scales: Celsius [60C], Fahrenheit [140F],\n"
- "\t\t Kelvin [350K], Rankine [600R] and Reaumur [50Re]\n"
- "\t\tOnly integer values allowed."),
- OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
- OPT_INC('q', "quiet", verbose, OPT_NEGATIVE, "\tQuiet (the more -q, the more quiet)"),
- OPT_INT('b', "black-magic", black_magic, OPT_MULTIPLE, "<strength>\tUse black magic to make the tea extraordinary delicious.\n\t\tMay be specified more than once to describe the amounts of black magic to be invoked in each step of tea boiling."),
- OPT_BOOL('p', "pray", pray, OPT_SINGLE, "\tPray before boiling"),
- OPT_STRING(OPT_POSITIONAL(1), NULL, first_tea, OPT_REQUIRED | OPT_NO_HELP, ""),
- OPT_CALL(OPT_POSITIONAL_TAIL, NULL, add_tea, &tea_list, OPT_NO_HELP, ""),
- OPT_HELP(""),
- OPT_HELP("Water options:"),
- OPT_SECTION(water_options),
- OPT_HOOK(opt_test_hook, "prearg", OPT_HOOK_BEFORE_ARG),
- OPT_HOOK(opt_test_hook, "preval", OPT_HOOK_BEFORE_VALUE),
- OPT_HOOK(opt_test_hook, "postval", OPT_HOOK_AFTER_VALUE),
- OPT_BOOL('H', "show-hooks", show_hooks, 0, "Demonstrate the hooks."),
- OPT_CONF_OPTIONS,
- OPT_END
- }
-};
-
-struct intnode {
- cnode n;
- int x;
-};
-
-int main(int argc UNUSED, char ** argv)
-{
- clist_init(&black_magic);
- opt_parse(&help, argv+1);
-
- printf("English style: %s|", english ? "yes" : "no");
- if (sugar)
- printf("Sugar: %d teaspoons|", sugar);
- if (set != -1)
- printf("Chosen teapot: %s|", teapot_type_str[set]);
- printf("Temperature: %d%s|", temperature.value, temp_scale_str[temperature.scale]);
- printf("Verbosity: %d|", verbose);
- CLIST_FOR_EACH(struct intnode *, n, black_magic)
- printf("Black magic: %d|", n->x);
- printf("Prayer: %s|", pray ? "yes" : "no");
- printf("Water amount: %d|", water_amount);
- printf("Gas: %s|", with_gas ? "yes" : "no");
- printf("First tea: %s|", first_tea);
- for (int i=0; i<tea_num; i++)
- printf("Boiling a tea: %s|", tea_list[i]);
-
- printf("Everything OK. Bye.\n");
-}
-
-#endif
# Tests of the command line option parser
Name: Opt-1
-Run: ( ../obj/ucw/opt-t 2>&1 1>/dev/null || [ $? -eq "2" ] ) | tr -d '\n'
+Run: ( ../obj/ucw/opt-test 2>&1 1>/dev/null || [ $? -eq "2" ] ) | tr -d '\n'
Out: Required option -t not found.Run with argument --help for more information.
Name: Opt-2
-Run: ../obj/ucw/opt-t -t95C -w640 -gG darjeeling
+Run: ../obj/ucw/opt-test -t95C -w640 -gG darjeeling
Out: English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye.
Name: Opt-3
-Run: ../obj/ucw/opt-t -vvqvqvhpe -t120F -w4 darjeeling
+Run: ../obj/ucw/opt-test -vvqvqvhpe -t120F -w4 darjeeling
Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 3|Prayer: yes|Water amount: 4|Gas: no|First tea: darjeeling|Everything OK. Bye.
Name: Opt-4
-Run: ../obj/ucw/opt-t -t120F -w4 puerh darjeeling earl-gray
+Run: ../obj/ucw/opt-test -t120F -w4 puerh darjeeling earl-gray
Out: English style: no|Temperature: 120F|Verbosity: 1|Prayer: no|Water amount: 4|Gas: no|First tea: puerh|Boiling a tea: darjeeling|Boiling a tea: earl-gray|Everything OK. Bye.
Name: Opt-5
-Run: ( ../obj/ucw/opt-t -ghx 2>&1 1>/dev/null || [ $? -eq "2" ] ) | tr -d '\n'
+Run: ( ../obj/ucw/opt-test -ghx 2>&1 1>/dev/null || [ $? -eq "2" ] ) | tr -d '\n'
Out: Multiple switches: -hRun with argument --help for more information.
Name: Opt-6
-Run: ../obj/ucw/opt-t -t120F -w4 -b15 -he -- --puerh darjeeling earl-gray
+Run: ../obj/ucw/opt-test -t120F -w4 -b15 -he -- --puerh darjeeling earl-gray
Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 1|Black magic: 15|Prayer: no|Water amount: 4|Gas: no|First tea: --puerh|Boiling a tea: darjeeling|Boiling a tea: earl-gray|Everything OK. Bye.
Name: Opt-7
-Run: ../obj/ucw/opt-t -t120F -w4 -b15 -b54 -he -- --puerh darjeeling earl-gray
+Run: ../obj/ucw/opt-test -t120F -w4 -b15 -b54 -he -- --puerh darjeeling earl-gray
Out: English style: yes|Chosen teapot: hands|Temperature: 120F|Verbosity: 1|Black magic: 15|Black magic: 54|Prayer: no|Water amount: 4|Gas: no|First tea: --puerh|Boiling a tea: darjeeling|Boiling a tea: earl-gray|Everything OK. Bye.
Name: Opt-Conf-1
-Run: ( ../obj/ucw/opt-t -h --dumpconfig 2>&1 1>/dev/null || [ $? -eq "2" ] ) | tr -d '\n'
+Run: ( ../obj/ucw/opt-test -h --dumpconfig 2>&1 1>/dev/null || [ $? -eq "2" ] ) | tr -d '\n'
Out: Config options (-C, -S) must stand before other options.Run with argument --help for more information.
Name: Opt-Hook-1
-Run: ../obj/ucw/opt-t -Ht 95C -w640 -gG darjeeling
+Run: ../obj/ucw/opt-test -Ht 95C -w640 -gG darjeeling
Out: [HOOK-postval:H/show-hooks=(null)] [HOOK-preval:t/temperature=95C] [HOOK-postval:t/temperature=95C] [HOOK-prearg] [HOOK-preval:w/water=640] [HOOK-postval:w/water=640] [HOOK-prearg] [HOOK-preval:g/glass-set=(null)] [HOOK-postval:g/glass-set=(null)] [HOOK-preval:G/with-gas=(null)] [HOOK-postval:G/with-gas=(null)] [HOOK-prearg] [HOOK-preval:\ 1/(null)=darjeeling] [HOOK-postval:\ 1/(null)=darjeeling] English style: no|Chosen teapot: glass|Temperature: 95C|Verbosity: 1|Prayer: no|Water amount: 640|Gas: yes|First tea: darjeeling|Everything OK. Bye.