HelenOS sources

root/uspace/lib/clui/src/nchoice.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nchoice_create
  2. nchoice_destroy
  3. nchoice_set_prompt
  4. nchoice_add
  5. nchoice_get

/*
 * 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 <errno.h>
#include <nchoice.h>
#include <stdio.h>
#include <stdlib.h>
#include <str.h>
#include <tinput.h>

/** 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;
}

/** @}
 */

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub