/* * Copyright (c) 2015 Jiri Svoboda * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup libclui * @{ */ /** * @file Numerical choice */ #include #include #include #include #include #include /** Create numerical choice * */ errno_t nchoice_create(nchoice_t **rchoice) { nchoice_t *choice = NULL; errno_t rc; choice = calloc(1, sizeof(nchoice_t)); if (choice == NULL) goto error; list_initialize(&choice->opts); choice->tinput = tinput_new(); if (choice->tinput == NULL) goto error; rc = tinput_set_prompt(choice->tinput, "Choice> "); if (rc != EOK) { assert(rc == ENOMEM); goto error; } *rchoice = choice; return EOK; error: nchoice_destroy(choice); return ENOMEM; } /** Destroy numerical choice */ void nchoice_destroy(nchoice_t *choice) { if (choice == NULL) return; tinput_destroy(choice->tinput); free(choice); } /** Set numerica choice prompt text */ errno_t nchoice_set_prompt(nchoice_t *choice, const char *prompt) { char *pstr; pstr = str_dup(prompt); if (pstr == NULL) return ENOMEM; free(choice->prompt); choice->prompt = pstr; return EOK; } /** Add option to numerical choice */ errno_t nchoice_add(nchoice_t *choice, const char *opttext, void *arg, nchoice_flag_t flags) { nchoice_opt_t *opt; char *ptext; opt = calloc(1, sizeof(nchoice_opt_t)); if (opt == NULL) return ENOMEM; ptext = str_dup(opttext); if (ptext == NULL) { free(opt); return ENOMEM; } opt->text = ptext; opt->arg = arg; list_append(&opt->lchoice, &choice->opts); if ((flags & ncf_default) != 0) { /* Set this option as the default */ assert(choice->def_opt == NULL); choice->def_opt = opt; } return EOK; } /** Get numerical choice from user */ errno_t nchoice_get(nchoice_t *choice, void **rarg) { int i; errno_t rc; int ret; char *str; unsigned long c; char *eptr; char *istr; int def_i; again: printf("%s\n", choice->prompt); def_i = 0; i = 1; list_foreach(choice->opts, lchoice, nchoice_opt_t, opt) { printf("%d: %s%s\n", i, opt->text, opt == choice->def_opt ? " [default]" : ""); if (opt == choice->def_opt) def_i = i; ++i; } if (def_i > 0) { ret = asprintf(&istr, "%d", def_i); if (ret < 0) return ENOMEM; } else { istr = str_dup(""); if (istr == NULL) return ENOMEM; } rc = tinput_read_i(choice->tinput, istr, &str); free(istr); if (rc != EOK) { assert(rc == EIO || rc == ENOENT); if (rc == ENOENT) { return ENOENT; } else { /* rc == EIO */ return EIO; } } c = strtoul(str, &eptr, 10); if (*eptr != '\0' || c < 1 || c > (unsigned long)i - 1) { printf("Invalid choice. Try again.\n"); free(str); goto again; } free(str); i = 1; list_foreach(choice->opts, lchoice, nchoice_opt_t, opt) { if ((unsigned long)i == c) { *rarg = opt->arg; return EOK; } ++i; } assert(false); return ENOENT; } /** @} */