/*======================================================================
 FILE: icalerror_p.c
 CREATOR: eric 16 May 1999

 SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>
 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
======================================================================*/

/*************************************************************************
 * WARNING: USE AT YOUR OWN RISK                                         *
 * These are library internal-only functions.                            *
 * Be warned that these functions can change at any time without notice. *
 *************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "icalerror_p.h"

#include <stdlib.h>

static ICAL_GLOBAL_VAR int foo;

void icalerror_stop_here(void)
{
    foo++; /* Keep optimizers from removing routine */
}

void icalerror_crash_here(void)
{
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
#endif
#if !defined(__clang_analyzer__)
    int *p = 0;
    /* coverity[var_deref_op] */
    /* cppcheck-suppress nullPointer */
    *p = 1;

    /* cppcheck-suppress nullPointer */
    icalassert(*p);
#endif
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
}

struct icalerror_state {
    icalerrorenum error;
    icalerrorstate state;
};

static ICAL_GLOBAL_VAR struct icalerror_state error_state_map[] = {
    {ICAL_BADARG_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_NEWFAILED_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_ALLOCATION_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_THREADING_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_MALFORMEDDATA_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_PARSE_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_INTERNAL_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_FILE_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_USAGE_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_UNIMPLEMENTED_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_UNKNOWN_ERROR, ICAL_ERROR_DEFAULT},
    {ICAL_NO_ERROR, ICAL_ERROR_DEFAULT}

};

struct icalerror_string_map {
    const char *str;
    icalerrorenum error;
    char name[160];
};

static const struct icalerror_string_map string_map[] = {
    {"BADARG", ICAL_BADARG_ERROR, "BADARG: Bad argument to function"},
    {"NEWFAILED", ICAL_NEWFAILED_ERROR,
     "NEWFAILED: Failed to create a new object via a *_new() routine"},
    {"ALLOCATION", ICAL_ALLOCATION_ERROR, "ALLOCATION: Failed to allocate new memory"},
    {"THREADING", ICAL_THREADING_ERROR, "Failing to lock or unlock threads"},
    {"MALFORMEDDATA", ICAL_MALFORMEDDATA_ERROR,
     "MALFORMEDDATA: An input string was not correctly formed or a component has "
     "missing or extra properties"},
    {"PARSE", ICAL_PARSE_ERROR, "PARSE: Failed to parse a part of an iCal component"},
    {"INTERNAL", ICAL_INTERNAL_ERROR,
     "INTERNAL: Random internal error. This indicates an error in the library code, "
     "not an error in use"},
    {"FILE", ICAL_FILE_ERROR,
     "FILE: An operation on a file failed. Check errno for more detail."},
    {"USAGE", ICAL_USAGE_ERROR,
     "USAGE: Failed to propertyl sequence calls to a set of interfaces"},
    {"UNIMPLEMENTED", ICAL_UNIMPLEMENTED_ERROR,
     "UNIMPLEMENTED: This feature has not been implemented"},
    {"NO", ICAL_NO_ERROR, "NO: No error"},
    {"UNKNOWN", ICAL_UNKNOWN_ERROR,
     "UNKNOWN: Unknown error type -- icalerror_strerror() was probably given bad input"}};

icalerrorenum icalerror_error_from_string(const char *str)
{
    int i;

    for (i = 0; string_map[i].error != ICAL_UNKNOWN_ERROR; i++) {
        if (strcmp(string_map[i].str, str) == 0) {
            break;
        }
    }

    return string_map[i].error;
}

icalerrorstate icalerror_supress(const char *error)
{
    icalerrorenum e = icalerror_error_from_string(error);
    icalerrorstate es;

    if (e == ICAL_NO_ERROR) {
        return ICAL_ERROR_UNKNOWN;
    }

    es = icalerror_get_error_state(e);
    icalerror_set_error_state(e, ICAL_ERROR_NONFATAL);

    return es;
}

const char *icalerror_perror(void)
{
    return icalerror_strerror(icalerrno);
}

void icalerror_restore(const char *error, icalerrorstate es)
{
    icalerrorenum e = icalerror_error_from_string(error);

    if (e != ICAL_NO_ERROR) {
        icalerror_set_error_state(e, es);
    }
}

void icalerror_set_error_state(icalerrorenum error, icalerrorstate state)
{
    int i;

    for (i = 0; error_state_map[i].error != ICAL_NO_ERROR; i++) {
        if (error_state_map[i].error == error) {
            error_state_map[i].state = state;
        }
    }
}

icalerrorstate icalerror_get_error_state(icalerrorenum error)
{
    int i;

    for (i = 0; error_state_map[i].error != ICAL_NO_ERROR; i++) {
        if (error_state_map[i].error == error) {
            return error_state_map[i].state;
        }
    }

    return ICAL_ERROR_UNKNOWN;
}

const char *icalerror_strerror(icalerrorenum e)
{
    int i;

    for (i = 0; string_map[i].error != ICAL_UNKNOWN_ERROR; i++) {
        if (string_map[i].error == e) {
            return string_map[i].name;
        }
    }

    return string_map[i].name; /* Return string for ICAL_UNKNOWN_ERROR */
}
