/* * Written 2016 by Andre Noll * * Public domain, no copyright claims. */ #include #include #include #include #include #include #include #include #include "lopsub.h" #include "lopsubex.lsg.h" typedef int (*example_handler_t)(struct lls_parse_result *); struct local_command_info { example_handler_t handler; }; #define EXPORT_CMD(_cmd) \ const struct local_command_info lsg_lopsubex_com_ ## _cmd ## _user_data = { \ .handler = com_ ## _cmd \ }; #define CMD_PTR(_cmd) lls_cmd(LSG_LOPSUBEX_CMD_ ## _cmd, lopsubex_suite) #define OPT_PTR(_cmd, _opt) \ lls_opt(LSG_LOPSUBEX_ ## _cmd ## _OPT_ ## _opt, CMD_PTR(_cmd)) #define OPT_RESULT(_cmd, _opt, _lpr) \ lls_opt_result(LSG_LOPSUBEX_ ## _cmd ## _OPT_ ## _opt, _lpr) static void print_available_commands(void) { const struct lls_command *cmd; int i; printf("Available subcommands:\n"); for (i = 1; (cmd = lls_cmd(i, lopsubex_suite)); i++) { const char *name = lls_command_name(cmd); const char *purpose = lls_purpose(cmd); printf("%-20s%s\n", name, purpose); } } static const struct lls_command *lookup_subcmd_or_die(const char *str) { char *errctx; int ret = lls_lookup_subcmd(str, lopsubex_suite, &errctx); if (ret < 0) { if (errctx) printf("%s: ", errctx); printf("%s\n", lls_strerror(-ret)); print_available_commands(); exit(EXIT_FAILURE); } return lls_cmd(ret, lopsubex_suite); } static int com_flag(struct lls_parse_result *lpr) { const struct lls_opt_result *r = OPT_RESULT(FLAG, SIMPLE, lpr); /* flag count is obtained with lls_given() */ printf("--simple is given %u times\n", lls_opt_given(r)); r = OPT_RESULT(FLAG, SQRT4, lpr); printf("--sqrt4 (aka -2) is given %u times\n", lls_opt_given(r)); return 0; } EXPORT_CMD(flag) static int com_int_param(struct lls_parse_result *lpr) { const struct lls_opt_result *r_r = OPT_RESULT(INT_PARAM, ROTATE, lpr); printf("rotating by %d degrees\n", lls_int32_val(0, r_r)); return 0; } EXPORT_CMD(int_param) static int com_multiple(struct lls_parse_result *lpr) { const struct lls_opt_result *r; int i; unsigned given; r = OPT_RESULT(MULTIPLE, VERBOSE, lpr); printf("--verbose is given %d times\n", lls_opt_given(r)); r = OPT_RESULT(MULTIPLE, INPUT_FILE, lpr); given = lls_opt_given(r); printf("--input-file is given %d times\n", lls_opt_given(r)); for (i = 0; i < given; i++) printf("--input-file val #%d: %s\n", i, lls_string_val(i, r)); r = OPT_RESULT(MULTIPLE, OUTPUT_FILE, lpr); printf("--output-file is given %d times\n", lls_opt_given(r)); printf("--output-file val: %s\n", lls_string_val(0, r)); return 0; } EXPORT_CMD(multiple) static int com_custom_synopsis(struct lls_parse_result *lpr) { const struct lls_command *cmd = CMD_PTR(CUSTOM_SYNOPSIS); char *long_help = lls_long_help(cmd); printf("%s\n", long_help); free(long_help); return 0; } EXPORT_CMD(custom_synopsis) static void fruit_salad(struct lls_parse_result *lpr) { const struct lls_opt_result *r_f = OPT_RESULT(SERIALIZE, FRUIT, lpr); const struct lls_opt_result *r_a = OPT_RESULT(SERIALIZE, AMOUNT, lpr); const struct lls_opt_result *r_s = OPT_RESULT(SERIALIZE, SUGAR, lpr); const struct lls_opt_result *r_c = OPT_RESULT(SERIALIZE, CONTAINER, lpr); int i, num_vals; printf("Put %d gramms of fruits (", lls_uint32_val(0, r_a)); num_vals = lls_opt_given(r_f) > 0? lls_opt_given(r_f) : 1; for (i = 0; i < num_vals; i++) printf("%s%s", lls_string_val(i, r_f), i == num_vals - 1? "" : ", "); printf(") in a %s, ", lls_string_val(0, r_c)); if (lls_opt_given(r_s)) printf("add sugar, "); printf("and serve cold.\n"); } static int com_serialize(struct lls_parse_result *lpr) { const struct lls_command *cmd = CMD_PTR(SERIALIZE); char *buf = NULL; int ret; size_t nbytes; struct lls_parse_result *dlpr; /* deserialized */ fruit_salad(lpr); ret = lls_serialize_parse_result(lpr, cmd, &buf, &nbytes); if (ret < 0) return ret; printf("serialized parse result into %zu byte buffer\n", nbytes); ret = lls_deserialize_parse_result(buf, cmd, &dlpr); free(buf); if (ret < 0) return ret; printf("successfully deserialized parse result\n"); fruit_salad(dlpr); lls_free_parse_result(dlpr, cmd); return 1; } EXPORT_CMD(serialize) static int com_non_ascii(struct lls_parse_result *lpr) { const struct lls_opt_result *r_c = OPT_RESULT(NON_ASCII, CITY, lpr); const char *city = lls_string_val(0, r_c); if (strcmp(city, "Göttingen")) printf("I don't know anything about %s\n", city); else printf("One of the most famous citicens of Göttingen was\n" "the mathematician Carl Friedrich Gauß.\n"); exit(EXIT_SUCCESS); } EXPORT_CMD(non_ascii) static int com_enum(struct lls_parse_result *lpr) { const struct lls_option *o_c = OPT_PTR(ENUM, COLOR); const struct lls_opt_result *r_c = OPT_RESULT(ENUM, COLOR, lpr); bool c_given = lls_opt_given(r_c); uint32_t num; const char *color; num = lls_uint32_val(0, r_c); color = lls_enum_string_val(num, o_c); printf("%s value: #%d: %s\n", c_given? "good" : "default", num, color); printf("Band names containing '%s'\n", color); switch (num) { case COLOR_RED: printf("Red Snapper\n"); printf("Red Lorry Yellow Lorry\n"); break; case COLOR_GREEN: printf("Green Day\n"); printf("Green Jelly\n"); break; case COLOR_BLUE: printf("Blue Cheer\n"); printf("Blue Öyster Cult\n"); break; default: printf("Nothing appropriate\n"); } if (!c_given) { printf("Available colors:\n"); for (num = 0; num < LSG_NUM_LOPSUBEX_ENUM_COLOR_VALUES; num++) printf("color #%d: %s\n", num, lls_enum_string_val(num, o_c)); } return 1; } EXPORT_CMD(enum) static int com_quotes(struct lls_parse_result *lpr) { const struct lls_opt_result *r_s = OPT_RESULT(QUOTES, CHARS, lpr); const char *val= lls_string_val(0, r_s); printf("Special characters: %s\n", val); return 0; } EXPORT_CMD(quotes) static int com_help(struct lls_parse_result *lpr) { const struct lls_command *cmd = CMD_PTR(HELP); const struct lls_opt_result *r_l = OPT_RESULT(HELP, LONG, lpr); char *txt; int ret; ret = lls_check_arg_count(lpr, 0, 1, NULL); if (ret < 0) return ret; if (lls_num_inputs(lpr) > 0) cmd = lookup_subcmd_or_die(lls_input(0, lpr)); if (lls_opt_given(r_l)) txt = lls_long_help(cmd); else txt = lls_short_help(cmd); printf("%s", txt); free(txt); return 0; } EXPORT_CMD(help) static int com_default_val(struct lls_parse_result *lpr) { const struct lls_opt_result *r; uint32_t val1, val2; const char *txt1, *txt2; r = OPT_RESULT(DEFAULT_VAL, WIDTH, lpr); val1 = lls_uint32_val(0, r); r = OPT_RESULT(DEFAULT_VAL, HEIGHT, lpr); val2 = lls_uint32_val(0, r); printf("geometry: %" PRIu32 "x%" PRIu32 "\n", val1, val2); r = OPT_RESULT(DEFAULT_VAL, TOWN, lpr); txt1 = lls_string_val(0, r); r = OPT_RESULT(DEFAULT_VAL, STREET, lpr); txt2 = lls_string_val(0, r); printf("address: %s, %s\n", txt2, txt1); r = OPT_RESULT(DEFAULT_VAL, TIME, lpr); val1 = lls_uint32_val(0, r); txt1 = lls_enum_string_val(val1, OPT_PTR(DEFAULT_VAL, TIME)); r = OPT_RESULT(DEFAULT_VAL, WEEKDAY, lpr); val2 = lls_uint32_val(0, r); txt2 = lls_enum_string_val(val2, OPT_PTR(DEFAULT_VAL, WEEKDAY)); printf("when: %s %s\n", txt2, txt1); return 0; } EXPORT_CMD(default_val) static int com_optional_arg(struct lls_parse_result *lpr) { const struct lls_opt_result *r; r = OPT_RESULT(OPTIONAL_ARG, WIDTH, lpr); printf("width: %u (%u times given)\n", lls_uint32_val(0, r), lls_opt_given(r)); r = OPT_RESULT(OPTIONAL_ARG, HEIGHT, lpr); printf("height: %u (%u times given)\n", lls_uint32_val(0, r), lls_opt_given(r)); printf("%u non-option arguments\n", lls_num_inputs(lpr)); return 0; } EXPORT_CMD(optional_arg) /* stringify the first argument (author information) */ #define LOPSUBEX_AUX_INFO(_author, _perms) #_author, static const char * const authors[] = {LSG_LOPSUBEX_AUX_INFOS}; #undef LOPSUBEX_AUX_INFO #define LOPSUBEX_AUX_INFO(_author, _perms) _perms, static const mode_t permissions[] = {LSG_LOPSUBEX_AUX_INFOS}; static int com_aux_info(struct lls_parse_result *lpr) { const struct lls_command *cmd; int i; for (i = 0; (cmd = lls_cmd(i, lopsubex_suite)); i++) { const char *name = lls_command_name(cmd); printf("%s: ", name); printf("author: %s, permissions: %o\n", authors[i], permissions[i]); } return 0; } EXPORT_CMD(aux_info) int main(int argc, char **argv) { int ret; const struct lls_command *cmd; struct lls_parse_result *lpr; const struct local_command_info *lci; char *errctx; if (argc <= 1) { printf("Usage: %s [options]\n", argv[0]); print_available_commands(); exit(EXIT_FAILURE); } cmd = lookup_subcmd_or_die(argv[1]); ret = lls_parse(argc - 1, argv + 1, cmd, &lpr, &errctx); if (ret < 0) { printf("%s: %s\n", errctx, lls_strerror(-ret)); free(errctx); exit(EXIT_FAILURE); } lci = lls_user_data(cmd); ret = lci->handler(lpr); lls_free_parse_result(lpr, cmd); exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS); }