/*
 * Copyright 2012-2020 the Pacemaker project contributors
 *
 * The version control history for this file may have further details.
 *
 * This source code is licensed under the GNU General Public License version 2
 * or later (GPLv2+) WITHOUT ANY WARRANTY.
 */

#include <crm_internal.h>

#include <crm/crm.h>

/* *INDENT-OFF* */
static struct crm_option long_options[] = {
    /* Top-level Options */
    {"help",       0, 0, '?', "\tThis text"},
    {"version",    0, 0, '$', "\tVersion information"  },
    {"verbose",    0, 0, 'V', "\tIncrease debug output"},

    {"name",    0, 0, 'n', "\tShow the error's name rather than the description."
     "\n\t\t\tUseful for looking for sources of the error in source code"},

    {"list",    0, 0, 'l', "\tShow all known errors."},
    {"rc",      0, 0, 'r', "\tInterpret as return code rather than legacy function return value"},

    {0, 0, 0, 0}
};
/* *INDENT-ON* */

static bool as_rc = false;

static void
get_strings(int rc, const char **name, const char **str)
{
    if (as_rc) {
        *str = pcmk_rc_str(rc);
        *name = pcmk_rc_name(rc);
    } else {
        *str = pcmk_strerror(rc);
        *name = pcmk_errorname(rc);
    }
}

int
main(int argc, char **argv)
{
    int rc = 0;
    int lpc = 0;
    int flag = 0;
    int option_index = 0;

    bool do_list = FALSE;
    bool with_name = FALSE;

    const char *name = NULL;
    const char *desc = NULL;

    crm_log_cli_init("crm_error");
    crm_set_options(NULL, "[options] -- <rc> [...]", long_options,
                    "Tool for displaying the textual name or description of a reported error code");

    while (flag >= 0) {
        flag = crm_get_option(argc, argv, &option_index);
        switch (flag) {
            case -1:
                break;
            case 'V':
                crm_bump_log_level(argc, argv);
                break;
            case '$':
            case '?':
                crm_help(flag, EX_OK);
                break;
            case 'n':
                with_name = TRUE;
                break;
            case 'l':
                do_list = TRUE;
                break;
            case 'r':
                as_rc = true;
                break;
            default:
                crm_help(flag, EX_OK);
                break;
        }
    }

    if(do_list) {
        int start, end, width;

        // 256 is a hacky magic number that "should" be enough
        if (as_rc) {
            start = pcmk_rc_error - 256;
            end = PCMK_CUSTOM_OFFSET;
            width = 4;
        } else {
            start = 0;
            end = 256;
            width = 3;
        }

        for (rc = start; rc < end; rc++) {
            if (rc == (pcmk_rc_error + 1)) {
                // Values in between are reserved for callers, no use iterating
                rc = pcmk_rc_ok;
            }
            get_strings(rc, &name, &desc);
            if(name == NULL || strcmp("Unknown", name) == 0) {
                // Undefined
            } else if(with_name) {
                printf("% .*d: %-26s  %s\n", width, rc, name, desc);
            } else {
                printf("% .*d: %s\n", width, rc, desc);
            }
        }

    } else {
        for (lpc = optind; lpc < argc; lpc++) {
            rc = crm_atoi(argv[lpc], NULL);
            get_strings(rc, &name, &desc);
            if (with_name) {
                printf("%s - %s\n", name, desc);
            } else {
                printf("%s\n", desc);
            }
        }
    }
    return 0;
}
