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).

There are also a few things that I wasn't sure and I'd really appreciate
some help:

   - Logging priorities (EINA_ERROR_LEVEL and domain level): is the code
   with the correct priorities? (lines 1064 to 1071 of eina_error.c)
   - Domain slots: from the tests results, it looks like the slot code is
   working, but I'm not sure it doesn't have a case which will break
   - Levels: is INT32_MAX a good value for the UNKNOWN level (which is
   basically just a placeholder. Whenever you log and it's UNKNOWN, your domain
   will use global level)
   - Old API: I redirected the old API to a global logger which is
   registered on eina_error_init(). Is this OK?


-- 
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_rectangle.c
===================================================================
--- src/tests/eina_test_rectangle.c	(revision 41406)
+++ src/tests/eina_test_rectangle.c	(working copy)
@@ -36,7 +36,7 @@
 
    eina_rectangle_init();
 
-   pool = eina_rectangle_pool_add(256, 256);
+   pool = eina_rectangle_pool_new(256, 256);
    fail_if(pool == NULL);
 
    eina_rectangle_pool_data_set(pool, rects);
@@ -66,7 +66,7 @@
 
    fail_if(eina_rectangle_pool_request(pool, 16, 16) == NULL);
 
-   eina_rectangle_pool_delete(pool);
+   eina_rectangle_pool_free(pool);
 
    eina_rectangle_shutdown();
 }
Index: src/tests/eina_test_error.c
===================================================================
--- src/tests/eina_test_error.c	(revision 41406)
+++ src/tests/eina_test_error.c	(working copy)
@@ -77,10 +77,85 @@
 }
 END_TEST
 
+START_TEST(eina_error_domains_macros)
+{
+   eina_error_init();
+
+   Eina_Error_Domain_Index i = eina_error_domain_register("MyDomain", EINA_COLOR_GREEN);
+   fail_if(i == -1);
+
+   EINA_ERROR_PERR_DOM(i, "An error\n");
+   EINA_ERROR_PINFO_DOM(i, "An info\n");
+   EINA_ERROR_PWARN_DOM(i, "A warning\n");
+   EINA_ERROR_PDBG_DOM(i, "A debug\n");
+
+   eina_error_shutdown();
+}
+END_TEST
+
+START_TEST(eina_error_domains_registry)
+{
+   eina_error_init();
+
+   int i;
+   Eina_Error_Domain_Index idx[50];
+
+   for (i = 0; i < 50; i++)
+     {
+	idx[i] = eina_error_domain_register("Test", EINA_COLOR_GREEN);
+	fail_if(idx[i] == -1);
+     }
+
+   for (i = 0; i < 50; i++)
+      eina_error_domain_unregister(idx[i]);
+
+   eina_error_shutdown();
+}
+END_TEST
+
+START_TEST(eina_error_domains_slot_reuse)
+{
+   eina_error_init();
+
+   // Create 9 domains
+   Eina_Error_Domain_Index idx[9];
+   int i;
+
+   for (i = 0; i < 9; i++)
+     {
+	idx[i] = eina_error_domain_register("Test1", EINA_COLOR_GREEN);
+	fail_if(idx[i] == -1);
+     }
+
+   // 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.
+
+   Eina_Error_Domain_Index removed = idx[5];
+   eina_error_domain_unregister(removed);
+
+   Eina_Error_Domain_Index new = eina_error_domain_register("Test1", EINA_COLOR_GREEN);
+
+   // Check for slot reuse
+   fail_if(new != idx[5]);
+
+   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 41406)
+++ src/include/eina_error.h	(working copy)
@@ -20,9 +20,19 @@
 #define EINA_ERROR_H_
 
 #include <stdarg.h>
+#include <stdint.h>
 
 #include "eina_types.h"
+#include "eina_inlist.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 +45,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 +93,32 @@
 #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;
+typedef struct _Eina_Error_Domain_Level_Pending Eina_Error_Domain_Level_Pending;
+typedef int Eina_Error_Domain_Index;
+
+struct _Eina_Error_Domain
+{
+   EINA_INLIST;
+
+   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 */
+};
+
+struct _Eina_Error_Domain_Level_Pending
+{
+   EINA_INLIST;
+
+   const char *name;
+   unsigned int level;
+};
+
+
 /**
  * @typedef Eina_Error_Level
  * List of available error levels.
@@ -86,7 +134,8 @@
 	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 +144,7 @@
  */
 typedef int Eina_Error;
 
+
 /**
  * @typedef Eina_Error_Print_Cb
  * Type for print callbacks.
@@ -103,6 +153,10 @@
                 const char *fnc, int line, const char *fmt, void *data,
 		va_list args);
 
+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);
+
 /**
  * @var EINA_ERROR_OUT_OF_MEMORY
  * Error identifier corresponding to a lack of memory.
@@ -129,6 +183,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 Eina_Error_Domain_Index eina_error_domain_register(const char *name, const char *color);
+EAPI void eina_error_domain_unregister(Eina_Error_Domain_Index i);
+
+EAPI void eina_error_dom_print(Eina_Error_Domain_Index i, 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(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);
+EAPI void eina_error_dom_print_cb_file(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);
+
 /**
  * @}
  */
Index: src/lib/eina_error.c
===================================================================
--- src/lib/eina_error.c	(revision 41406)
+++ src/lib/eina_error.c	(working copy)
@@ -381,18 +381,31 @@
  */
 
 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;
+/*
+ * 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;
+static int _pending_list_count = 0;
+
+/*
+ * 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;
 #else
@@ -400,12 +413,124 @@
 #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_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, int name_len, const char *color, int color_len)
+{
+   const char *d;
+
+   if (color && color_len)
+     {
+	d = malloc(sizeof(char) * (color_len + name_len + strlen(EINA_COLOR_WHITE) + 1));
+	memcpy((char *)d, color, color_len);
+	memcpy((char *)(d + color_len), name, name_len);
+	memcpy((char *)(d + color_len + name_len), EINA_COLOR_WHITE, strlen(EINA_COLOR_WHITE));
+	((char *)d)[color_len + name_len + strlen(EINA_COLOR_WHITE)] = '\0';
+     }
+   else
+     {
+	d = malloc(sizeof(char) * (name_len + 1));
+	memcpy((char *)d, name, name_len);
+	((char *)d)[name_len] = '\0';
+     }
+   return d;
+}
+
+static Eina_Error_Domain *
+eina_error_domain_new(const char *name, const char *color)
+{
+   Eina_Error_Domain *d;
+   size_t len;
+
+   d = malloc(sizeof(Eina_Error_Domain));
+   if (!d) return NULL;
+
+   d->level = EINA_ERROR_LEVEL_UNKNOWN;
+   d->deleted = 0;
+
+   if (color)
+     {
+	d->color = malloc(sizeof(char)*(strlen(color)+1));
+	memcpy((char *)d->color, color, strlen(color));
+	((char *)d->color)[strlen(color)] = '\0';
+     }
+   else
+      d->color = NULL;
+
+   if (name)
+     {
+	len = strlen(name);
+	d->name = malloc(sizeof(char)*(len + 1));
+	memcpy((char *)d->name, name, len);
+	((char *)d->name)[len] = '\0';
+	if (color)
+	   d->domain_str = eina_error_domain_str_get(name, len, color, strlen(color));
+	else
+	   d->domain_str = eina_error_domain_str_get(name, len, NULL, 0);
+     }
+   else
+     {
+	d->name = NULL;
+	d->domain_str = NULL;
+     }
+
+   return d;
+}
+
+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);
+}
+
+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_ERROR_DOMAIN_LEVELS")))
+     {
+      return;
+     }
+
+   // Form name:level,name1:level1,name2:level2,...
+   start = l;
+   while (1)
+     {
+	end = strchr(start, ':');
+	if (!end) break;
+
+	// Parse name
+	p = malloc(sizeof(Eina_Error_Domain_Level_Pending) + end - start);
+	p->name = (char *)p + sizeof(Eina_Error_Domain_Level_Pending);
+	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));
+	_pending_list_count++;
+
+	fprintf(stderr, "Parsed %s level %d\n", p->name, p->level);
+	start = tmp + 1;
+     }
+}
+
 /**
  * @endcond
  */
@@ -490,6 +615,8 @@
 
 EAPI Eina_Error EINA_ERROR_OUT_OF_MEMORY = 0;
 
+EAPI int EINA_ERROR_DOMAIN_GLOBAL = 0;
+
 /**
  * @endcond
  */
@@ -524,18 +651,30 @@
  */
 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)
+     {
+	char *level;
+	char *tmp;
+
+	/* TODO register the eina's basic errors */
+	if ((level = getenv("EINA_ERROR_LEVEL")))
+	   _error_level = atoi(level);
+	else
+	   _error_level = EINA_ERROR_LEVEL_UNKNOWN;
+
+	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, NULL);
+
+	// Check if color is disabled
+	if ((tmp = getenv("EINA_ERROR_COLOR_DISABLE")))
+	  if (atoi(tmp) == 1) _disable_color = 1;
+
+	eina_error_domain_parse_pendings();
+     }
+
+   return ++_eina_error_init_count;
 }
 
 /**
@@ -568,6 +707,21 @@
 			free(tmp);
 		}
 		_error_list_count = 0;
+
+		while (_error_domains_count--)
+		  {
+		     if (_error_domains[_error_domains_count])
+			eina_error_domain_free(_error_domains[_error_domains_count]);
+		  }
+		free(_error_domains);
+
+		while (_pending_list)
+		{
+		     tmp = _pending_list;
+		     _pending_list = _pending_list->next;
+		     free(tmp);
+		}
+
 	}
 	return _eina_error_init_count;
 }
@@ -733,10 +887,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(EINA_ERROR_DOMAIN_GLOBAL, level, file, fnc, line, fmt, data, args);
 }
 
 /**
@@ -760,10 +911,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(EINA_ERROR_DOMAIN_GLOBAL, level, file, fnc, line, fmt, data, args);
 }
 
 /**
@@ -795,6 +943,144 @@
 	_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.
+ */
+EAPI Eina_Error_Domain_Index
+eina_error_domain_register(const char *name, const char *color)
+{
+   Eina_Error_Domain_Level_Pending *pending;
+   int i, id;
+
+   for (i = 0; i < _error_domains_count; i++)
+     {
+	if (!_error_domains[i])
+	  {
+	     // NULL slot
+	     fprintf(stderr, "Found a null slot at idx %d\n", i);
+	     _error_domains[i] = eina_error_domain_new(name, color);
+	     if (!(_error_domains[i])) return -1;
+	     goto finish_register;
+	  }
+	if (_error_domains[i]->deleted)
+	  {
+	     // Found a flagged slot
+	     fprintf(stderr, "Found a deleted flag slot at %d\n", i);
+	     eina_error_domain_free(_error_domains[i]);
+	     _error_domains[i] = eina_error_domain_new(name, color);
+	     if (!_error_domains[i]) return -1;
+	     goto finish_register;
+	  }
+     }
+
+   // Did not found a slot, realloc 8 more slots. Also works on the first time
+   // when the array doesn't exist yet.
+   _error_domains = realloc(_error_domains, sizeof(Eina_Error_Domain)*8);
+
+   // Flag empty slots.
+   for (id = _error_domains_count; id <= _error_domains_count + 8; id++)
+     {
+	_error_domains[id] = NULL;
+     }
+
+   _error_domains_count += 8;
+
+   // Use the index of the for loop. If it reached the end with no slots,
+   // then we gotta insert on i+1. If it's 0, then the array is empty and
+   // we should insert on 0.
+   if (i) _error_domains[++i] = eina_error_domain_new(name, color);
+   else _error_domains[i] = eina_error_domain_new(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));
+	     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;
+
+   return i;
+}
+
+EAPI void
+eina_error_domain_unregister(Eina_Error_Domain_Index i)
+{
+   if (i >= _error_domains_count) return;
+   _error_domains[i]->deleted = 1;
+}
+
+EAPI void
+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);
+}
+
+EAPI void
+eina_error_dom_print_cb_file(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)
+{
+	// Workaround to use var level.
+	Eina_Error_Level x = level;
+	x++;
+
+	FILE *f = data;
+	Eina_Error_Domain *d;
+	d = _error_domains[i];
+	fprintf(f, "%s\t%s:%d %s() ", (d->name) ? d->name : "", file, line, fnc);
+	vfprintf(f, fmt, args);
+}
+
+EAPI void
+eina_error_dom_print(Eina_Error_Domain_Index i, Eina_Error_Level level, const char *file,
+		const char *fnc, int line, const char *fmt, ...)
+{
+	va_list args;
+
+	if (level > _error_level)
+	  {
+		return;
+	  }
+	else if (level > _error_domains[i]->level)
+	  {
+		return;
+	  }
+
+	EINA_SAFETY_ON_NULL_RETURN(file);
+	EINA_SAFETY_ON_NULL_RETURN(fnc);
+	EINA_SAFETY_ON_NULL_RETURN(fmt);
+
+	va_start(args, fmt);
+	_dom_print_cb(i, level, file, fnc, line, fmt, _print_cb_data, args);
+	va_end(args);
+
+	if (getenv("EINA_ERROR_ABORT")) abort();
+}
+
 /**
  * @}
  */
------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge  
This is your chance to win up to $100,000 in prizes! For a limited time, 
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize  
details at: http://p.sf.net/sfu/Challenge
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to