/* EINA - EFL data type library * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Cedric Bail * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; * if not, see . */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #ifdef HAVE_EVIL # include #endif #include "eina_config.h" #include "eina_private.h" /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ #include "eina_safety_checks.h" #include "eina_error.h" #include "eina_stringshare.h" /* TODO * + add a wrapper for assert? * + add common error numbers, messages * + add a calltrace of errors, not only store the last error but a list of them * and also store the function that set it */ /*============================================================================* * Local * *============================================================================*/ /** * @cond LOCAL */ typedef struct _Eina_Error_Message Eina_Error_Message; struct _Eina_Error_Message { Eina_Bool string_allocated; const char *string; }; static Eina_Error_Message *_eina_errors = NULL; static size_t _eina_errors_count = 0; static size_t _eina_errors_allocated = 0; static Eina_Error _eina_last_error; static Eina_Error_Message * _eina_error_msg_alloc(void) { size_t idx; if (_eina_errors_count == _eina_errors_allocated) { void *tmp; size_t size; if (EINA_UNLIKELY(_eina_errors_allocated == 0)) size = 24; else size = _eina_errors_allocated + 8; tmp = realloc(_eina_errors, sizeof(Eina_Error_Message) * size); if (!tmp) return NULL; _eina_errors = tmp; _eina_errors_allocated = size; } idx = _eina_errors_count; _eina_errors_count++; return _eina_errors + idx; } /** * @endcond */ /*============================================================================* * Global * *============================================================================*/ /** * @cond LOCAL */ EAPI Eina_Error EINA_ERROR_OUT_OF_MEMORY = 0; static const char EINA_ERROR_OUT_OF_MEMORY_STR[] = "Out of memory"; /** * @endcond */ /** * @internal * @brief Initialize the error module. * * @return #EINA_TRUE on success, #EINA_FALSE on failure. * * This function sets up the error module of Eina. It is called by * eina_init(). * * This function registers the error #EINA_ERROR_OUT_OF_MEMORY. * * @see eina_init() */ Eina_Bool eina_error_init(void) { /* TODO register the eina's basic errors */ EINA_ERROR_OUT_OF_MEMORY = eina_error_msg_static_register( EINA_ERROR_OUT_OF_MEMORY_STR); return EINA_TRUE; } /** * @internal * @brief Shut down the error module. * * @return #EINA_TRUE on success, #EINA_FALSE on failure. * * This function shuts down the error module set up by * eina_error_init(). It is called by eina_shutdown(). * * @see eina_shutdown() */ Eina_Bool eina_error_shutdown(void) { Eina_Error_Message *eem, *eem_end; eem = _eina_errors; eem_end = eem + _eina_errors_count; for (; eem < eem_end; eem++) if (eem->string_allocated) eina_stringshare_del(eem->string); free(_eina_errors); _eina_errors = NULL; _eina_errors_count = 0; _eina_errors_allocated = 0; return EINA_TRUE; } /*============================================================================* * API * *============================================================================*/ EAPI Eina_Error eina_error_msg_register(const char *msg) { Eina_Error_Message *eem; EINA_SAFETY_ON_NULL_RETURN_VAL(msg, 0); eem = _eina_error_msg_alloc(); if (!eem) return 0; eem->string_allocated = EINA_TRUE; eem->string = eina_stringshare_add(msg); if (!eem->string) { _eina_errors_count--; return 0; } return _eina_errors_count; /* identifier = index + 1 (== _count). */ } EAPI Eina_Error eina_error_msg_static_register(const char *msg) { Eina_Error_Message *eem; EINA_SAFETY_ON_NULL_RETURN_VAL(msg, 0); eem = _eina_error_msg_alloc(); if (!eem) return 0; eem->string_allocated = EINA_FALSE; eem->string = msg; return _eina_errors_count; /* identifier = index + 1 (== _count). */ } EAPI Eina_Bool eina_error_msg_modify(Eina_Error error, const char *msg) { EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE); if (error < 1) return EINA_FALSE; if ((size_t)error > _eina_errors_count) return EINA_FALSE; if (_eina_errors[error - 1].string_allocated) { const char *tmp; if (!(tmp = eina_stringshare_add(msg))) return EINA_FALSE; eina_stringshare_del(_eina_errors[error - 1].string); _eina_errors[error - 1].string = tmp; return EINA_TRUE; } _eina_errors[error - 1].string = msg; return EINA_TRUE; } EAPI const char * eina_error_msg_get(Eina_Error error) { if (error < 1) return NULL; if ((size_t)error > _eina_errors_count) return NULL; return _eina_errors[error - 1].string; } EAPI Eina_Error eina_error_get(void) { return _eina_last_error; } EAPI void eina_error_set(Eina_Error err) { _eina_last_error = err; } EAPI Eina_Error eina_error_find(const char *msg) { size_t i; EINA_SAFETY_ON_NULL_RETURN_VAL(msg, 0); for (i = 0; i < _eina_errors_count; i++) { if (_eina_errors[i].string_allocated) { if (_eina_errors[i].string == msg) return i + 1; } if (!strcmp(_eina_errors[i].string, msg)) return i + 1; } return 0; }