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

Reply via email to