Removing workaround with unused variable.. On Sat, Jul 25, 2009 at 10:30 PM, Andre Dieb <andre.mart...@ee.ufcg.edu.br>wrote:
> Fix a missing free() spotted by Sachiel. > > > On Sat, Jul 25, 2009 at 9:21 PM, Andre Dieb > <andre.mart...@ee.ufcg.edu.br>wrote: > >> The new patch is attached (hope it works now). >> >> >> On Sat, Jul 25, 2009 at 9:04 PM, Andre Dieb <andre.mart...@ee.ufcg.edu.br >> > wrote: >> >>> The new patch is attached. >>> >>> On Sat, Jul 18, 2009 at 1:57 PM, Gustavo Sverzut Barbieri >>> <barbi...@profusion.mobi> wrote: >>> >>>> On Fri, Jul 17, 2009 at 6:55 PM, Andre Dieb< >>>> andre.mart...@ee.ufcg.edu.br> wrote: >>>> > Hello, >>>> > >>>> > This patch contains an initial implementation of logging domains for >>>> eina >>>> > error module. Please be aware that this a very rough version and there >>>> are >>>> > lots of things that must be improved. >>>> > >>>> > The patch is also with lots of fprintf's that I was using for >>>> debugging, >>>> > please ignore them. When we're ready to apply, I'll cleanup >>>> everything. >>>> > >>>> > For testing the new domain features, I added three unit tests and >>>> fixed >>>> > eina_rectangle test that was preventing me from building eina_error >>>> test. >>>> > You can also see examples of how logging domains will be used on these >>>> tests >>>> > (registering, logging, unregistering). >>>> >>>> Okay, couple of issues. One of them was already spotted by Sachiel, >>>> but other follows: >>>> >>>> Header: >>>> >>>> +typedef int Eina_Error_Domain_Index; >>>> >>>> this typedef is a bit too much. >>>> >>>> +struct _Eina_Error_Domain >>>> +{ >>>> + EINA_INLIST; >>>> >>>> ouch, this is legacy and not being used! Remove it. >>>> >>>> + unsigned int level; /**< Max level to log */ >>>> + const char *name; /**< Domain name */ >>>> + const char *domain_str; /**< Formatted string with color to print */ >>>> + const char *color; >>>> + >>>> + /* Private */ >>>> + int deleted : 1; /**< Flags deletion of domain, a free slot */ >>>> >>>> Eina_Bool, otherwise deleted is just the sign bit and deleted is (-1, >>>> 0), not (1, 0) >>>> >>>> >>>> +typedef struct _Eina_Error_Domain_Level_Pending >>>> Eina_Error_Domain_Level_Pending >>>> +struct _Eina_Error_Domain_Level_Pending >>>> >>>> These are private to eina_error.c >>>> >>>> +struct _Eina_Error_Domain_Level_Pending >>>> +{ >>>> + EINA_INLIST; >>>> + >>>> + const char *name; >>>> + unsigned int level; >>>> +}; >>>> >>>> change to the following and get the pointer arithmetic for free, also >>>> saving one pointer access and sizeof(char*) bytes.: >>>> +struct _Eina_Error_Domain_Level_Pending >>>> +{ >>>> + EINA_INLIST; >>>> + >>>> + unsigned int level; >>>> char name[]; >>>> +}; >>>> >>>> +typedef void (*Eina_Error_Dom_Print_Cb)(Eina_Error_Domain_Index i, >>>> Eina_Error_Level level, const char *file, >>>> + const char *fnc, int line, const char *fmt, void *data, >>>> + va_list args); >>>> + >>>> >>>> and all other callbacks: domain index is useless, you should give it >>>> the pointer to domain! Imagine I want to implement my own logging in >>>> my program, how could I access the log domain? Other than that, domain >>>> index is pretty much useless. >>>> >>>> >>>> Code: >>>> >>>> +static Eina_Error_Domain **_error_domains = NULL; >>>> >>>> Sachiel spotted you're misusing the _error_domains by allocating >>>> sizeof(Eina_Error_Domain) instead of pointer. But I guess this should >>>> be really an array of domains and not an array of pointers. So just >>>> change that to Eina_Error_Domain *_error_domains. That's why you need >>>> "domain->deleted", otherwise just free and set to NULL. The other >>>> option is to remove "deleted" and keep this as a pointer, but I guess >>>> it's marginally worse. >>>> >>>> +static int _error_domains_count = 0; >>>> >>>> see eina_array, you need 2 counters, one for current size (count) and >>>> another for allocated size. Then you do not need to memset()/NULL-ify >>>> remaining slots. If you want to avoid useless walks in this array, you >>>> can keep an extra "free" count, that would say the number of free >>>> slots inside _error_domains_count. It would increase when you remove >>>> elements before last. If you remove last, just decrease >>>> error_domains_count. If want to bit super-correct, when you remove >>>> last you'd walk backwards checking for already freed slots and move >>>> that amount from _free to _count. Ie: >>>> >>>> [xxxxx###], count=5, size=8, free=0 >>>> [xxx#x###], count=5, size=8, free=1 >>>> [xxx#####], count=3, size=8, free=0 >>>> >>>> >>>> +static int _pending_list_count = 0; >>>> >>>> remove, this is useless. >>>> >>>> >>>> + d = malloc(sizeof(char) * (color_len + name_len + >>>> strlen(EINA_COLOR_WHITE) + 1)); >>>> >>>> oops, don't assume everybody uses dark terminals! You should use >>>> EINA_COLOR_NOTHING. And while compiler should optimize strlen() for >>>> that string, you can remove that with sizeof(), and it already >>>> accounts trailing \0. Same for memcpy(), just give it sizeof() and it >>>> will copy the null terminator. >>>> >>>> + d->color = malloc(sizeof(char)*(strlen(color)+1)); >>>> + memcpy((char *)d->color, color, strlen(color)); >>>> >>>> you can just strdup() here. And while most compilers would optimize >>>> strlen(), keeping a variable with that value would make your code >>>> easier to read. >>>> >>>> if you allocate all the strings in a single memory blob, it's even >>>> better. >>>> >>>> >>>> +static void >>>> +eina_error_domain_free(Eina_Error_Domain *d) >>>> +{ >>>> + if (!d) return; >>>> + >>>> + if (d->name) >>>> + free((char *)d->name); >>>> + if (d->domain_str) >>>> + free((char *)d->domain_str); >>>> + >>>> + free(d); >>>> +} >>>> >>>> how about color? that's the benefit of using a single blob, just free >>>> the pointer that is the head, everything else goes aways >>>> automatically. >>>> >>>> + // Form name:level,name1:level1,name2:level2,... >>>> ... >>>> + p->level = strtol((char *)(end + 1), &tmp, 10); >>>> ... >>>> + start = tmp + 1; >>>> >>>> doc fail! :-) You need to strchr(tmp, ',') to find out next comma. >>>> Also add that doc (and other env vars!) to header. >>>> >>>> + EINA_ERROR_DOMAIN_GLOBAL = eina_error_domain_register(NULL, >>>> NULL); >>>> i guess it would be better to give real values to this function and >>>> actually make it complain on NULL pointers, also adding >>>> EINA_ARG_NONNULL() to header signature. >>>> >>>> >>>> + // Check if color is disabled >>>> + if ((tmp = getenv("EINA_ERROR_COLOR_DISABLE"))) >>>> + if (atoi(tmp) == 1) _disable_color = 1; >>>> do this before everything else, so functions that check for >>>> _disable_color will always consider it correctly. >>>> >>>> +finish_register: >>>> + EINA_INLIST_FOREACH(_pending_list, pending) >>>> + { >>>> + if (!strcmp(pending->name, name)) >>>> + { >>>> + fprintf(stderr, "Updating domain %s level from %d to %d\n", >>>> name, _error_domains[i]->level, pending->level); >>>> + _error_domains[i]->level = pending->level; >>>> + _pending_list = eina_inlist_remove(_pending_list, >>>> EINA_INLIST_GET(pending)); >>>> + break; >>>> + } >>>> + } >>>> >>>> oops, leaked pending! >>>> >>>> >>>> +eina_error_dom_print_cb_stdout(Eina_Error_Domain_Index i, >>>> Eina_Error_Level level, >>>> + const char *file, const char *fnc, int line, const char >>>> *fmt, >>>> + __UNUSED__ void *data, va_list args) >>>> +{ >>>> + Eina_Error_Domain *d; >>>> + d = _error_domains[i]; >>>> + >>>> + if (!d) return; >>>> + >>>> + printf("%s\t%s%s:%d %s()%s ", (d->domain_str) ? d->domain_str : >>>> ((d->name) ? d->name : ""), >>>> + (!_disable_color) ? _colors[level] : "", >>>> + file, line, fnc, >>>> + (!_disable_color) ? >>>> _colors[EINA_ERROR_LEVEL_INFO] : ""); >>>> + vprintf(fmt, args); >>>> +} >>>> >>>> just guarantee these strings will always be valid. And give this >>>> callback a const Eina_Error_Domain. The point of having domain_str and >>>> name is to avoid doing these checks during every print. >>>> >>>> + >>>> + if (getenv("EINA_ERROR_ABORT")) abort(); >>>> +} >>>> >>>> this is bad and would make abort on any debug if its level is visible. >>>> Just check if level is greater than error/critical/whatever. >>>> >>>> All in all it looks good, just fix these points and I'll commit. >>>> >>>> -- >>>> Gustavo Sverzut Barbieri >>>> http://profusion.mobi embedded systems >>>> -------------------------------------- >>>> MSN: barbi...@gmail.com >>>> Skype: gsbarbieri >>>> Mobile: +55 (19) 9225-2202 >>>> >>> >>> >>> >>> -- >>> André Dieb Martins >>> >>> Embedded Systems and Pervasive Computing Lab (Embedded) >>> Electrical Engineering Department (DEE) >>> Center of Electrical Engineering and Informatics (CEEI) >>> Federal University of Campina Grande (UFCG) >>> >>> Blog: http://genuinepulse.blogspot.com/ >>> >> >> >> >> -- >> André Dieb Martins >> >> Embedded Systems and Pervasive Computing Lab (Embedded) >> Electrical Engineering Department (DEE) >> Center of Electrical Engineering and Informatics (CEEI) >> Federal University of Campina Grande (UFCG) >> >> Blog: http://genuinepulse.blogspot.com/ >> > > > > -- > André Dieb Martins > > Embedded Systems and Pervasive Computing Lab (Embedded) > Electrical Engineering Department (DEE) > Center of Electrical Engineering and Informatics (CEEI) > Federal University of Campina Grande (UFCG) > > Blog: http://genuinepulse.blogspot.com/ > -- André Dieb Martins Embedded Systems and Pervasive Computing Lab (Embedded) Electrical Engineering Department (DEE) Center of Electrical Engineering and Informatics (CEEI) Federal University of Campina Grande (UFCG) Blog: http://genuinepulse.blogspot.com/
Index: src/tests/eina_test_error.c =================================================================== --- src/tests/eina_test_error.c (revision 41496) +++ src/tests/eina_test_error.c (working copy) @@ -29,14 +29,17 @@ START_TEST(eina_error_init_shutdown) { - eina_error_init(); - eina_error_init(); - eina_error_shutdown(); - eina_error_init(); - eina_error_init(); - eina_error_shutdown(); - eina_error_shutdown(); - eina_error_shutdown(); + int initial_level = eina_error_init() - 1; + fail_if(!initial_level); + + fail_if(!eina_error_init()); + fail_if(!eina_error_shutdown()); + fail_if(!eina_error_init()); + fail_if(!eina_error_init()); + fail_if(!eina_error_shutdown()); + fail_if(!eina_error_shutdown()); + + fail_if(initial_level != eina_error_shutdown()); } END_TEST @@ -48,7 +51,7 @@ setenv("EINA_ERROR_LEVEL", "1", 0); - eina_error_init(); + fail_if(!eina_error_init()); test = eina_error_msg_register(TEST_TEXT); fail_if(!eina_error_msg_get(test)); @@ -63,7 +66,7 @@ START_TEST(eina_error_macro) { - eina_error_init(); + fail_if(!eina_error_init()); eina_error_log_level_set(EINA_ERROR_LEVEL_DBG); eina_error_print_cb_set(eina_error_print_cb_file, stderr); @@ -77,10 +80,85 @@ } END_TEST +START_TEST(eina_error_domains_macros) +{ + fail_if(!eina_error_init()); + + int d = eina_error_domain_register("MyDomain", EINA_COLOR_GREEN); + fail_if(d < 0); + + EINA_ERROR_PERR_DOM(d, "An error\n"); + EINA_ERROR_PINFO_DOM(d, "An info\n"); + EINA_ERROR_PWARN_DOM(d, "A warning\n"); + EINA_ERROR_PDBG_DOM(d, "A debug\n"); + + eina_error_shutdown(); +} +END_TEST + +START_TEST(eina_error_domains_registry) +{ + fail_if(!eina_error_init()); + + int i; + int d[50]; + + for (i = 0; i < 50; i++) + { + d[i] = eina_error_domain_register("Test", EINA_COLOR_GREEN); + fail_if(d[i] < 0); + } + + for (i = 0; i < 50; i++) + eina_error_domain_unregister(d[i]); + + eina_error_shutdown(); +} +END_TEST + +START_TEST(eina_error_domains_slot_reuse) +{ + fail_if(!eina_error_init()); + + // Create 9 domains + int idx[9]; + int i; + + for (i = 0; i < 9; i++) + { + idx[i] = eina_error_domain_register("Test1", EINA_COLOR_GREEN); + fail_if(idx[i] < 0); + } + + // Slot 0 by default contains the global logger. The above code created + // domains for slots indexes from 1 to 9. + // + // The global logger allocated the first 8 initial slots. The 8th domain + // registered on the for loop will create 8 more slots. + // + // Test will just unregister a domain between 1 and 9 and assure that a new + // domain register will be placed on the available slot and not at the end. + + int removed = idx[5]; + eina_error_domain_unregister(removed); + + int new = eina_error_domain_register("Test Slot", EINA_COLOR_GREEN); + + // Check for slot reuse + fail_if(new != removed); + + eina_error_shutdown(); +} +END_TEST + + void eina_test_error(TCase *tc) { tcase_add_test(tc, eina_error_init_shutdown); tcase_add_test(tc, eina_error_errno); tcase_add_test(tc, eina_error_macro); + tcase_add_test(tc, eina_error_domains_macros); + tcase_add_test(tc, eina_error_domains_registry); + tcase_add_test(tc, eina_error_domains_slot_reuse); } Index: src/include/eina_error.h =================================================================== --- src/include/eina_error.h (revision 41496) +++ src/include/eina_error.h (working copy) @@ -20,9 +20,18 @@ #define EINA_ERROR_H_ #include <stdarg.h> +#include <stdint.h> #include "eina_types.h" +#define EINA_COLOR_RED "\033[31;1m" +#define EINA_COLOR_BLUE "\033[34;1m" +#define EINA_COLOR_GREEN "\033[32;1m" +#define EINA_COLOR_YELLOW "\033[33;1m" +#define EINA_COLOR_WHITE "\033[37;1m" +#define EINA_COLOR_LIGHTBLUE "\033[36;1m" +#define EINA_COLOR_NOTHING "\033[0m" + /** * @addtogroup Eina_Tools_Group Tools * @@ -35,6 +44,18 @@ * @{ */ +#define EINA_ERROR_PERR_DOM(DOM, fmt, ...) \ + eina_error_dom_print(DOM, EINA_ERROR_LEVEL_ERR, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) + +#define EINA_ERROR_PINFO_DOM(DOM, fmt, ...) \ + eina_error_dom_print(DOM, EINA_ERROR_LEVEL_INFO, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) + +#define EINA_ERROR_PDBG_DOM(DOM, fmt, ...) \ + eina_error_dom_print(DOM, EINA_ERROR_LEVEL_DBG, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) + +#define EINA_ERROR_PWARN_DOM(DOM, fmt, ...) \ + eina_error_dom_print(DOM, EINA_ERROR_LEVEL_WARN, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) + /** * @def EINA_ERROR_PERR(fmt, ...) * Print the error message described with the formatted string @a fmt @@ -71,6 +92,19 @@ #define EINA_ERROR_PDBG(fmt, ...) \ eina_error_print(EINA_ERROR_LEVEL_DBG, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) +typedef struct _Eina_Error_Domain Eina_Error_Domain; + +struct _Eina_Error_Domain +{ + unsigned int level; /**< Max level to log */ + const char *domain_str; /**< Formatted string with color to print */ + + /* Private */ + Eina_Bool deleted:1; /**< Flags deletion of domain, a free slot */ +}; + + + /** * @typedef Eina_Error_Level * List of available error levels. @@ -82,11 +116,13 @@ */ typedef enum _Eina_Error_Level { + EINA_ERROR_LEVEL_CRITICAL, /**< Critical error level */ EINA_ERROR_LEVEL_ERR, /**< Error error level */ EINA_ERROR_LEVEL_WARN, /**< Warning error level */ EINA_ERROR_LEVEL_INFO, /**< Information error level */ EINA_ERROR_LEVEL_DBG, /**< Debug error level */ - EINA_ERROR_LEVELS /**< Count of error level */ + EINA_ERROR_LEVELS, /**< Count of error level */ + EINA_ERROR_LEVEL_UNKNOWN = INT32_MAX } Eina_Error_Level; /** @@ -95,6 +131,7 @@ */ typedef int Eina_Error; + /** * @typedef Eina_Error_Print_Cb * Type for print callbacks. @@ -103,6 +140,10 @@ const char *fnc, int line, const char *fmt, void *data, va_list args); +typedef void (*Eina_Error_Dom_Print_Cb)(const Eina_Error_Domain *d, Eina_Error_Level level, const char *file, + const char *fnc, int line, const char *fmt, void *data, + va_list args); + /** * @var EINA_ERROR_OUT_OF_MEMORY * Error identifier corresponding to a lack of memory. @@ -129,6 +170,13 @@ EAPI void eina_error_print_cb_set(Eina_Error_Print_Cb cb, void *data) EINA_ARG_NONNULL(1); EAPI void eina_error_log_level_set(Eina_Error_Level level); +EAPI int eina_error_domain_register(const char *name, const char *color) EINA_ARG_NONNULL(1); +EAPI void eina_error_domain_unregister(int domain); + +EAPI void eina_error_dom_print(int domain, Eina_Error_Level level, const char *file, const char *function, int line, const char *fmt, ...) EINA_ARG_NONNULL(2, 3, 5); +EAPI void eina_error_dom_print_cb_stdout(const Eina_Error_Domain *d, Eina_Error_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args); +EAPI void eina_error_dom_print_cb_file(const Eina_Error_Domain *d, Eina_Error_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args); + /** * @} */ Index: src/lib/eina_error.c =================================================================== --- src/lib/eina_error.c (revision 41496) +++ src/lib/eina_error.c (working copy) @@ -380,32 +380,150 @@ * @cond LOCAL */ +#define EINA_ENV_ERROR_ABORT "EINA_ERROR_ABORT" +#define EINA_ENV_ERROR_LEVEL "EINA_ERROR_LEVEL" +#define EINA_ENV_ERROR_LEVELS "EINA_ERROR_LEVELS" +#define EINA_ENV_COLOR_DISABLE "EINA_ERROR_COLOR_DISABLE" + +typedef struct _Eina_Error_Domain_Level_Pending Eina_Error_Domain_Level_Pending; +struct _Eina_Error_Domain_Level_Pending +{ + EINA_INLIST; + + unsigned int level; + char name[]; +}; + static int _eina_error_init_count = 0; + +static int _disable_color = 0; + +/* + * List of domains registered + */ +static Eina_Error_Domain *_error_domains = NULL; +static int _error_domains_count = 0; +static int _error_domains_allocated = 0; + +/* + * List of levels for domains set by the user before the domains are registered, + * updates the domain levels on the first log and clears itself. + */ +static Eina_Inlist *_pending_list = NULL; + +/* + * List of errors registered + */ static Eina_Inlist *_error_list = NULL; static int _error_list_count = 0; static Eina_Error _err; static Eina_Error_Print_Cb _print_cb = eina_error_print_cb_stdout; +static Eina_Error_Dom_Print_Cb _dom_print_cb = eina_error_dom_print_cb_stdout; static void *_print_cb_data = NULL; -#define RED "\033[31;1m" -#define GREEN "\033[32;1m" -#define YELLOW "\033[33;1m" -#define WHITE "\033[37;1m" -#define NOTHING "\033[0m" - #ifdef DEBUG static Eina_Error_Level _error_level = EINA_ERROR_LEVEL_DBG; +#elif DEBUG_CRITICAL +static Eina_Error_Level _error_level = EINA_ERROR_LEVEL_CRITICAL; #else static Eina_Error_Level _error_level = EINA_ERROR_LEVEL_ERR; #endif static const char *_colors[EINA_ERROR_LEVELS] = { - RED, // EINA_ERROR_LEVEL_ERR - YELLOW, // EINA_ERROR_LEVEL_WARN - NOTHING, // EINA_ERROR_LEVEL_INFO - GREEN, // EINA_ERROR_LEVEL_DBG + EINA_COLOR_YELLOW, // EINA_ERROR_LEVEL_CRITICAL + EINA_COLOR_RED, // EINA_ERROR_LEVEL_ERR + EINA_COLOR_YELLOW, // EINA_ERROR_LEVEL_WARN + EINA_COLOR_NOTHING, // EINA_ERROR_LEVEL_INFO + EINA_COLOR_GREEN, // EINA_ERROR_LEVEL_DBG }; +static const char * +eina_error_domain_str_get(const char *name, const char *color) +{ + const char *d; + int name_len; + int color_len; + + if (color) + { + name_len = strlen(name); + color_len = strlen(color); + d = malloc(sizeof(char) * (color_len + name_len + strlen(EINA_COLOR_NOTHING) + 1)); + memcpy((char *)d, color, color_len); + memcpy((char *)(d + color_len), name, name_len); + memcpy((char *)(d + color_len + name_len), EINA_COLOR_NOTHING, strlen(EINA_COLOR_NOTHING)); + ((char *)d)[color_len + name_len + strlen(EINA_COLOR_NOTHING)] = '\0'; + } + else + d = strdup(name); + + return d; +} + +static Eina_Error_Domain * +eina_error_domain_new(Eina_Error_Domain *d, const char *name, const char *color) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + + d->level = EINA_ERROR_LEVEL_UNKNOWN; + d->deleted = 0; + + if (name) + { + if ((color) && (!_disable_color)) + d->domain_str = eina_error_domain_str_get(name, color); + else + d->domain_str = eina_error_domain_str_get(name, NULL); + } + else + d->domain_str = NULL; + + return d; +} + +static void +eina_error_domain_free(Eina_Error_Domain *d) +{ + EINA_SAFETY_ON_NULL_RETURN(d); + + if (d->domain_str) + free((char *)d->domain_str); +} + +static void eina_error_domain_parse_pendings(void) +{ + Eina_Error_Domain_Level_Pending *p; + char *l; + const char *start, *end; + char *tmp; + + if (!(l = getenv(EINA_ENV_ERROR_LEVELS))) return; + + // Form name:level,name1:level1,name2:level2,... + start = l; + while (1) + { + if (!start) break; + end = strchr(start, ':'); + if (!end) break; + + // Parse name + p = malloc(sizeof(Eina_Error_Domain_Level_Pending) + end - start); + memcpy((char *)p->name, start, end-start); + ((char *)p->name)[end - start] = '\0'; + + // Parse level + p->level = strtol((char *)(end + 1), &tmp, 10); + + _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(p)); + + fprintf(stderr, "Parsed %s level %d\n", p->name, p->level); + if (!tmp) break; + start = strchr(tmp, ','); + } +} + /** * @endcond */ @@ -490,6 +608,8 @@ EAPI Eina_Error EINA_ERROR_OUT_OF_MEMORY = 0; +EAPI int EINA_ERROR_DOMAIN_GLOBAL = 0; + /** * @endcond */ @@ -524,18 +644,36 @@ */ EAPI int eina_error_init(void) { - if (!_eina_error_init_count) - { - char *level; - /* TODO register the eina's basic errors */ - if ((level = getenv("EINA_ERROR_LEVEL"))) - { - _error_level = atoi(level); - } - EINA_ERROR_OUT_OF_MEMORY = eina_error_msg_register("Out of memory"); - } - /* get all the modules */ - return ++_eina_error_init_count; + if (_eina_error_init_count) return ++_eina_error_init_count; + + char *level; + char *tmp; + + // Check if color is disabled + if ((tmp = getenv(EINA_ENV_COLOR_DISABLE)) && (atoi(tmp) == 1)) + _disable_color = 1; + + if ((level = getenv(EINA_ENV_ERROR_LEVEL))) + _error_level = atoi(level); + else + _error_level = EINA_ERROR_LEVEL_ERR; + + // TODO register the eina's basic errors */ + EINA_ERROR_OUT_OF_MEMORY = eina_error_msg_register("Out of memory"); + + // Register UNKNOWN domain, the default logger + EINA_ERROR_DOMAIN_GLOBAL = eina_error_domain_register("", NULL); + + if (EINA_ERROR_DOMAIN_GLOBAL < 0) + { + fprintf(stderr, "Failed to create global logging domain.\n"); + return 0; + } + + // Parse pending domains passed through EINA_ERROR_LEVELS + eina_error_domain_parse_pendings(); + + return ++_eina_error_init_count; } /** @@ -554,35 +692,50 @@ */ EAPI int eina_error_shutdown(void) { - Eina_Inlist *tmp; + if (_eina_error_init_count != 1) return --_eina_error_init_count; - _eina_error_init_count--; - if (!_eina_error_init_count) - { - /* remove the error strings */ - while (_error_list) - { - tmp = _error_list; + Eina_Inlist *tmp; - _error_list = _error_list->next; - free(tmp); - } - _error_list_count = 0; - } - return _eina_error_init_count; + /* remove the error strings */ + while (_error_list) + { + tmp = _error_list; + _error_list = _error_list->next; + free(tmp); + } + + _error_list_count = 0; + + while (_error_domains_count--) + { + eina_error_domain_free(&_error_domains[_error_domains_count]); + } + + free(_error_domains); + + _error_domains = NULL; + + while (_pending_list) + { + tmp = _pending_list; + _pending_list = _pending_list->next; + free(tmp); + } + + return --_eina_error_init_count; } /** - * @brief Register a new error type. - * - * @param msg The description of the error. - * @return The unique number identifier for this error. - * - * This function stores in a list the error message described by - * @p msg. The returned value is a unique identifier greater or equal - * than 1. The description can be retrieve later by passing to - * eina_error_msg_get() the returned value. - */ +* @brief Register a new error type. +* +* @param msg The description of the error. +* @return The unique number identifier for this error. +* +* This function stores in a list the error message described by +* @p msg. The returned value is a unique identifier greater or equal +* than 1. The description can be retrieve later by passing to +* eina_error_msg_get() the returned value. +*/ EAPI Eina_Error eina_error_msg_register(const char *msg) { Eina_Inlist *tmp; @@ -696,7 +849,8 @@ _print_cb(level, file, fnc, line, fmt, _print_cb_data, args); va_end(args); - if (getenv("EINA_ERROR_ABORT")) abort(); + if ((getenv(EINA_ENV_ERROR_ABORT) && level <= EINA_ERROR_LEVEL_ERR)) + abort(); } EAPI void eina_error_vprint(Eina_Error_Level level, const char *file, @@ -711,7 +865,8 @@ _print_cb(level, file, fnc, line, fmt, _print_cb_data, args); - if (getenv("EINA_ERROR_ABORT")) abort(); + if ((getenv(EINA_ENV_ERROR_ABORT) && level <= EINA_ERROR_LEVEL_ERR)) + abort(); } /** @@ -733,10 +888,7 @@ const char *fnc, int line, const char *fmt, __UNUSED__ void *data, va_list args) { - printf("%s", _colors[level]); - printf("[%s:%d] %s() ", file, line, fnc); - printf("%s", _colors[EINA_ERROR_LEVEL_INFO]); - vprintf(fmt, args); + eina_error_dom_print_cb_stdout(&_error_domains[0], level, file, fnc, line, fmt, data, args); } /** @@ -760,10 +912,7 @@ const char *fnc, int line, const char *fmt, void *data, va_list args) { - FILE *f = data; - - fprintf(f, "[%s:%d] %s() ", file, line, fnc); - vfprintf(f, fmt, args); + eina_error_dom_print_cb_file(&_error_domains[0], level, file, fnc, line, fmt, data, args); } /** @@ -795,6 +944,143 @@ _error_level = level; } +/* + * @param name Domain name + * @param color Color of the domain name + * + * @return Domain index that will be used as the DOMAIN parameter on log + * macros. A negative return value means an error ocurred. + */ +EAPI int +eina_error_domain_register(const char *name, const char *color) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(name, 0); + + Eina_Error_Domain_Level_Pending *pending = NULL; + int i; + + for (i = 0; i < _error_domains_count; i++) + { + if (_error_domains[i].deleted) + { + // Found a flagged slot, free domain_str and replace slot + fprintf(stderr, "Found a deleted flag slot at %d\n", i); + eina_error_domain_free(&_error_domains[i]); + eina_error_domain_new(&_error_domains[i], name, color); + goto finish_register; + } + } + + if (_error_domains_count >= _error_domains_allocated) + { + fprintf(stderr, "No free slots, alocating more.\n"); + // Did not found a slot, realloc 8 more slots. Also works on the first time + // when the array doesn't exist yet. + Eina_Error_Domain *tmp = _error_domains; + + _error_domains_allocated += 8; + _error_domains = realloc(_error_domains, sizeof(Eina_Error_Domain)*_error_domains_allocated); + + fprintf(stderr, "After realloc call\n"); + + if (!_error_domains) + { + fprintf(stderr, "Could not alloc more domains.\n"); + _error_domains = tmp; + _error_domains_allocated -= 8; + return -1; + } + + fprintf(stderr, "Allocated successfully, alloc count is now %d\n", _error_domains_allocated); + } + + // Use an allocated slot + eina_error_domain_new(&_error_domains[i], name, color); + +finish_register: + + EINA_INLIST_FOREACH(_pending_list, pending) + { + if (!strcmp(pending->name, name)) + { + fprintf(stderr, "Updating domain %s level from %d to %d\n", name, _error_domains[i].level, pending->level); + _error_domains[i].level = pending->level; + _pending_list = eina_inlist_remove(_pending_list, EINA_INLIST_GET(pending)); + free(pending); + break; + } + } + + // Check if level is still UNKNOWN, set it to global + if (_error_domains[i].level == EINA_ERROR_LEVEL_UNKNOWN) + _error_domains[i].level = _error_level; + + _error_domains_count += 1; + return i; +} + +EAPI void +eina_error_domain_unregister(int domain) +{ + if (domain >= _error_domains_count) return; + + Eina_Error_Domain *d = &_error_domains[domain]; + d->deleted = 1; +} + +EAPI void +eina_error_dom_print_cb_stdout(const Eina_Error_Domain *d, Eina_Error_Level level, + const char *file, const char *fnc, int line, const char *fmt, + __UNUSED__ void *data, va_list args) +{ + EINA_SAFETY_ON_NULL_RETURN(d); + + printf("%s %s%s:%d %s()%s ", d->domain_str, + (!_disable_color) ? _colors[level] : "", + file, line, fnc, + (!_disable_color) ? EINA_COLOR_NOTHING: ""); + vprintf(fmt, args); +} + +EAPI void +eina_error_dom_print_cb_file(const Eina_Error_Domain *d, __UNUSED__ Eina_Error_Level level, + const char *file, const char *fnc, int line, const char *fmt, + void *data, va_list args) +{ + EINA_SAFETY_ON_NULL_RETURN(file); + EINA_SAFETY_ON_NULL_RETURN(fnc); + EINA_SAFETY_ON_NULL_RETURN(fmt); + + FILE *f = data; + fprintf(f, "%s %s:%d %s() ", d->domain_str, file, line, fnc); + vfprintf(f, fmt, args); +} + +EAPI void +eina_error_dom_print(int domain, Eina_Error_Level level, const char *file, + const char *fnc, int line, const char *fmt, ...) +{ + EINA_SAFETY_ON_NULL_RETURN(file); + EINA_SAFETY_ON_NULL_RETURN(fnc); + EINA_SAFETY_ON_NULL_RETURN(fmt); + + if (domain >= _error_domains_count) return; + if (domain < 0) return; + + Eina_Error_Domain *d = &_error_domains[domain]; + + if (level > d->level) return; + + va_list args; + + va_start(args, fmt); + _dom_print_cb(d, level, file, fnc, line, fmt, _print_cb_data, args); + va_end(args); + + if ((getenv(EINA_ENV_ERROR_ABORT) && level <= EINA_ERROR_LEVEL_ERR)) + abort(); +} + /** * @} */
------------------------------------------------------------------------------
_______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel