r4086 - in trunk/birnet: . tests
- From: timj svn gnome org
- To: svn-commits-list gnome org
- Subject: r4086 - in trunk/birnet: . tests
- Date: Mon, 20 Nov 2006 19:13:28 -0500 (EST)
Author: timj
Date: 2006-11-20 19:13:13 -0500 (Mon, 20 Nov 2006)
New Revision: 4086
Modified:
trunk/birnet/ChangeLog
trunk/birnet/birnetmsg.cc
trunk/birnet/birnetmsg.hh
trunk/birnet/birnetthread.cc
trunk/birnet/tests/infotest.cc
Log:
Mon Nov 20 23:39:43 2006 Tim Janik <timj gtk org>
* birnetmsg.hh, birnetmsg.cc: implemented C++ messaging API,
mostly based onthe former sfimsg.c.
extended API to match most of the old sfi_msg_* API, including
syslog logging, stdlog configuraiton and various new message types.
* birnetthread.cc: fixed missing zero initialization of C structs.
* tests/infotest.cc: added some message tests.
Modified: trunk/birnet/ChangeLog
===================================================================
--- trunk/birnet/ChangeLog 2006-11-15 15:08:43 UTC (rev 4085)
+++ trunk/birnet/ChangeLog 2006-11-21 00:13:13 UTC (rev 4086)
@@ -1,3 +1,14 @@
+Mon Nov 20 23:39:43 2006 Tim Janik <timj gtk org>
+
+ * birnetmsg.hh, birnetmsg.cc: implemented C++ messaging API,
+ mostly based onthe former sfimsg.c.
+ extended API to match most of the old sfi_msg_* API, including
+ syslog logging, stdlog configuraiton and various new message types.
+
+ * birnetthread.cc: fixed missing zero initialization of C structs.
+
+ * tests/infotest.cc: added some message tests.
+
Wed Nov 15 01:00:21 2006 Tim Janik <timj gtk org>
* birnetmath.hh, birnetmath.cc: added dtoi32, dtoi64, iround, iceil,
Modified: trunk/birnet/birnetmsg.cc
===================================================================
--- trunk/birnet/birnetmsg.cc 2006-11-15 15:08:43 UTC (rev 4085)
+++ trunk/birnet/birnetmsg.cc 2006-11-21 00:13:13 UTC (rev 4086)
@@ -18,7 +18,14 @@
*/
#include <glib.h>
#include "birnetmsg.hh"
+#include "birnetthread.hh"
+#include <syslog.h>
+#include <errno.h>
+#ifndef _ // FIXME
+#define _(x) (x)
+#endif
+
namespace Birnet {
Msg::Part::Part() :
@@ -45,11 +52,560 @@
const Msg::Part &Msg::empty_part = Part();
+volatile int Msg::n_msg_types = 0;
+uint8 *volatile Msg::msg_type_bits = NULL;
+
+struct MsgType {
+ /* this structure cannot use C++ types because it's not properly constructed */
+ const char *ident;
+ const char *label;
+ uint32 flags;
+ Msg::Type default_type;
+ bool enabled;
+};
+static Mutex msg_mutex;
+static MsgType* msg_types = NULL; /* cannot use a vector<> here, because of constructor ordering */
+static bool msg_log_to_stderr = true;
+static uint msg_syslog_priority = 0; // LOG_USER | LOG_INFO;
+static FILE *msg_log_file = NULL;
+
void
-Msg::display (const char *domain,
- const vector<Part> &parts)
+Msg::set_msg_type_L (uint mtype,
+ uint32 flags,
+ bool enabled)
{
- // FIXME: implement Msg::display()
+ /* adjust and uncouple mtype */
+ if (mtype < (uint) n_msg_types)
+ {
+ msg_types[mtype].flags = flags;
+ msg_types[mtype].enabled = enabled;
+ if (msg_types[mtype].flags && msg_types[mtype].enabled)
+ msg_type_bits[mtype / 8] |= 1 << mtype % 8;
+ else
+ msg_type_bits[mtype / 8] &= ~(1 << mtype % 8);
+ msg_types[mtype].default_type = (Type) mtype; /* uncouple from default_type */
+ BIRNET_ASSERT (mtype == (uint) msg_types[mtype].default_type);
+ }
+ /* adjust all types which default to mtype */
+ for (int i = mtype + 1; i < n_msg_types; i++)
+ if (mtype == (uint) msg_types[i].default_type)
+ {
+ msg_types[i].flags = flags;
+ msg_types[i].enabled = enabled;
+ if (msg_types[i].flags && msg_types[i].enabled)
+ msg_type_bits[i / 8] |= 1 << i % 8;
+ else
+ msg_type_bits[i / 8] &= ~(1 << i % 8);
+ }
}
+void
+Msg::init_standard_types()
+{
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized++;
+ Type mtype;
+ /* NONE (always disabled) */
+ mtype = register_type ("none", NONE, NULL);
+ BIRNET_ASSERT (mtype == NONE);
+ set_msg_type_L (mtype, NONE, false);
+ /* ALWAYS (always enabled) */
+ mtype = register_type ("always", ALWAYS, _("Always"));
+ BIRNET_ASSERT (mtype == ALWAYS);
+ set_msg_type_L (mtype, LOG_TO_STDERR | LOG_TO_STDLOG | LOG_TO_HANDLER, true);
+ /* ERROR (enabled) */
+ mtype = register_type ("error", ALWAYS, _("Error"));
+ BIRNET_ASSERT (mtype == ERROR);
+ set_msg_type_L (mtype, LOG_TO_STDERR | LOG_TO_STDLOG | LOG_TO_HANDLER, true);
+ /* WARNING (enabled) */
+ mtype = register_type ("warning", ALWAYS, _("Warning"));
+ BIRNET_ASSERT (mtype == WARNING);
+ set_msg_type_L (mtype, LOG_TO_STDERR | LOG_TO_STDLOG | LOG_TO_HANDLER, true);
+ /* SCRIPT (enabled) */
+ mtype = register_type ("script", ALWAYS, _("Script"));
+ BIRNET_ASSERT (mtype == SCRIPT);
+ set_msg_type_L (mtype, LOG_TO_STDERR | LOG_TO_STDLOG | LOG_TO_HANDLER, true);
+ /* INFO (enabled) */
+ mtype = register_type ("info", ALWAYS, _("Information"));
+ BIRNET_ASSERT (mtype == INFO);
+ set_msg_type_L (mtype, LOG_TO_STDERR | LOG_TO_STDLOG | LOG_TO_HANDLER, true);
+ /* DIAG (enabled) */
+ mtype = register_type ("diag", ALWAYS, _("Diagnostic"));
+ BIRNET_ASSERT (mtype == DIAG);
+ set_msg_type_L (mtype, LOG_TO_STDERR | LOG_TO_STDLOG, true);
+ /* DEBUG (disabled) */
+ mtype = register_type ("debug", NONE, "Debug");
+ set_msg_type_L (mtype, LOG_TO_STDERR, false);
+}
+
+/**
+ * @param ident message identifier
+ * @param default_ouput an existing SfiMsgType
+ * @param label a translated version of @a ident
+ * @return message type id
+ *
+ * Register a new message type with identifier @a ident and user digestible
+ * name @a label. If this function is called multiple times with the same
+ * identifier, the type id acquired by the first call will be returned
+ * and the other arguments are ignored.
+ * As long as the new message type isn't configured individually via
+ * msg_enable(), allow_msgs() or their complements, it shares
+ * the configuration of @a default_ouput. If NONE or ALWAYS is passed as
+ * @a default_ouput, this corresponds to the first two message types which
+ * are unconfigrable and always have their output disabled or enabled respectively.
+ * As an exception to the rest of the message API, this function may be
+ * called before birnet_init(). However note, that MT-safety is only ensured
+ * for calls occouring after birnet_init().
+ * This function is MT-safe and may be called from any thread.
+ */
+Msg::Type
+Msg::register_type (const char *ident,
+ Type default_ouput,
+ const char *label)
+{
+ /* ensure standard types are registered */
+ init_standard_types();
+ /* check arguments */
+ g_return_val_if_fail (ident != NULL, NONE);
+ if (default_ouput >= (int) n_msg_types)
+ default_ouput = NONE;
+ /* lock messages */
+ uint8 *old_mbits = NULL;
+ if (ThreadTable.mutex_lock)
+ msg_mutex.lock();
+ /* allow duplicate registration */
+ for (int i = 0; i < n_msg_types; i++)
+ if (strcmp (msg_types[i].ident, ident) == 0)
+ {
+ /* found duplicate */
+ if (ThreadTable.mutex_unlock)
+ msg_mutex.unlock();
+ return Type (i);
+ }
+ /* add new message type */
+ int n_mtypes = n_msg_types;
+ Type mtype = Type (n_mtypes++);
+ uint old_flags_size = (mtype + 7) / 8;
+ uint new_flags_size = (n_mtypes + 7) / 8;
+ if (old_flags_size < new_flags_size)
+ {
+ uint8 *mflags = g_new (guint8, new_flags_size);
+ memcpy (mflags, (uint8*) msg_type_bits, sizeof (msg_type_bits[0]) * old_flags_size);
+ mflags[new_flags_size - 1] = 0;
+ old_mbits = msg_type_bits;
+ /* we are holding a lock in the multi-threaded case so no need for compare_and_swap */
+ Atomic::ptr_set ((volatile uint8**) &msg_type_bits, mflags);
+ }
+ msg_types = g_renew (MsgType, msg_types, n_mtypes);
+ memset (&msg_types[mtype], 0, sizeof (msg_types[mtype]));
+ msg_types[mtype].ident = g_strdup (ident);
+ msg_types[mtype].label = g_strdup (label ? label : "");
+ msg_types[mtype].default_type = default_ouput; /* couple to default_ouput */
+ Atomic::int_set (&n_msg_types, n_mtypes); /* only ever grows */
+ /* adjust msg type config (after n_msg_types was incremented) */
+ set_msg_type_L (mtype, msg_types[default_ouput].flags, msg_types[default_ouput].enabled);
+ // FIXME: msg_type_bits should be registered as hazard pointer so we don't g_free() while other threads read old_mbits[*]
+ g_free (old_mbits);
+ if (ThreadTable.mutex_unlock)
+ msg_mutex.unlock();
+ return mtype;
+}
+
+static struct AutoConstruct {
+ AutoConstruct()
+ {
+ Msg::register_type ("none", Msg::NONE, "");
+ }
+} auto_construct;
+
+/**
+ * @param ident message identifier, e.g. "error", "warning", "info", etc...
+ * @return corresponding Type or 0
+ *
+ * Find the message type correspondign to @a ident. If no message
+ * type was found NONE is returned.
+ * This function is MT-safe and may be called from any thread.
+ */
+Msg::Type
+Msg::lookup_type (const String &ident)
+{
+ AutoLocker locker (msg_mutex);
+ for (int i = 0; i < n_msg_types; i++)
+ if (ident == msg_types[i].ident)
+ return Type (i);
+ return Msg::NONE;
+}
+
+void
+Msg::enable (Type mtype)
+{
+ AutoLocker locker (msg_mutex);
+ if (mtype > 1 && mtype < (int) n_msg_types)
+ set_msg_type_L (mtype, msg_types[mtype].flags, true);
+}
+
+void
+Msg::disable (Type mtype)
+{
+ AutoLocker locker (msg_mutex);
+ if (mtype > 1 && mtype < (int) n_msg_types)
+ set_msg_type_L (mtype, msg_types[mtype].flags, false);
+}
+
+
+/**
+ * @param type message type, e.g. Msg::ERROR, Msg::WARNING, Msg::INFO, etc...
+ * @return translated message identifier or NULL
+ *
+ * Retrive the string identifying the message type @a type. For invalid
+ * (non registered) message types, "" is returned.
+ * This function is MT-safe and may be called from any thread.
+ */
+const char*
+Msg::type_ident (Type mtype)
+{
+ AutoLocker locker (msg_mutex);
+ if (mtype >= 0 && mtype < n_msg_types)
+ return msg_types[mtype].ident;
+ return NULL;
+}
+
+/**
+ * @param type message type, e.g. Msg::ERROR, Msg::WARNING, Msg::INFO, etc...
+ * @return translated message identifier or NULL
+ *
+ * Retrive the label identifying the message type @a type. Usually,
+ * this is a translated version of Msg::type_ident() or ""
+ * if non was registered with the message type.
+ * This function is MT-safe and may be called from any thread.
+ */
+const char*
+Msg::type_label (Type mtype)
+{
+ AutoLocker locker (msg_mutex);
+ if (mtype >= 0 && mtype < n_msg_types)
+ return msg_types[mtype].label;
+ return NULL;
+}
+
+uint32
+Msg::type_flags (Type mtype)
+{
+ uint flags = 0;
+ AutoLocker locker (msg_mutex);
+ if (mtype >= 0 && mtype < n_msg_types)
+ flags = msg_types[mtype].flags;
+ return flags;
+}
+
+void
+Msg::configure (Type mtype,
+ LogFlags log_mask,
+ const String &logfile)
+{
+ AutoLocker locker (msg_mutex);
+ if (mtype > 1 && mtype < n_msg_types)
+ set_msg_type_L (mtype, log_mask, msg_types[mtype].enabled);
+}
+
+void
+Msg::key_list_change_L (const String &keylist,
+ bool isenabled)
+{
+ /* ensure all keywords are enclosed in ':' */
+ String s = ":" + keylist + ":";
+ /* allow ',' seperation and collapse spaces */
+ uint n = 0;
+ for (uint i = 0; s[i]; i++)
+ if (s[i] == ',')
+ s[n++] = ':';
+ else if (s[i] != ' ' && s[i] != '\t' && s[i] != '\n' && s[i] != '\r')
+ s[n++] = s[i];
+ s[n] = 0;
+ /* handle :all: special case */
+ if (strstr (s.c_str(), ":all:"))
+ {
+ for (int i = DEBUG; i < n_msg_types; i++)
+ set_msg_type_L (i, msg_types[i].flags, isenabled);
+ return;
+ }
+
+ /* walk all kyes */
+ String::size_type k = 1;
+ String::size_type c = s.find (':', k);
+ while (c)
+ {
+ if (k < c)
+ {
+ s[c] = 0;
+ int i;
+ for (i = DEBUG; i < n_msg_types; i++)
+ if (String (s.c_str() + k) == msg_types[i].ident)
+ break;
+ if (i < n_msg_types)
+ set_msg_type_L (i, msg_types[i].flags, isenabled);
+ }
+ k = c + 1;
+ c = s.find (':', k);
+ }
+}
+
+void
+Msg::allow_msgs (const String &key)
+{
+ AutoLocker locker (msg_mutex);
+ if (key.size())
+ key_list_change_L (key, true);
+#if 0
+ for (uint i = 0; i < n_msg_types; i++)
+ g_printerr ("% 2d) %s: enabled=%d flags=0x%x label=%s cache=%d\n", i,
+ msg_types[i].ident, msg_types[i].enabled,
+ msg_types[i].flags, msg_types[i].label,
+ check (i));
+#endif
+}
+
+void
+Msg::deny_msgs (const String &key)
+{
+ AutoLocker locker (msg_mutex);
+ if (key.size())
+ key_list_change_L (key, false);
+}
+
+void
+Msg::configure_stdlog (bool redirect_stdlog_to_stderr,
+ const String &stdlog_filename,
+ uint syslog_priority)
+{
+ AutoLocker locker (msg_mutex);
+ msg_log_to_stderr = redirect_stdlog_to_stderr;
+ if (msg_log_file && msg_log_file != stdout && msg_log_file != stderr)
+ fclose (msg_log_file);
+ msg_log_file = NULL;
+ if (stdlog_filename == "-")
+ msg_log_file = stdout;
+ else if (stdlog_filename.size())
+ msg_log_file = fopen (stdlog_filename.c_str(), "a");
+ msg_syslog_priority = syslog_priority;
+}
+
+static String
+prgname (bool maystrip)
+{
+ const gchar *pname = g_get_prgname();
+ if (pname && maystrip)
+ {
+ const gchar *p = strrchr (pname, '/');
+ pname = p ? p + 1 : pname;
+ }
+ return pname;
+}
+
+static String
+log_prefix (const String &prg_name,
+ uint pid,
+ const String &log_domain,
+ const String &label,
+ const String &ident)
+{
+ String str = prg_name;
+ if (pid)
+ str += string_printf ("[%u]", pid);
+ if (str.size() && *str.rbegin() != ':')
+ str += ":";
+ str += log_domain;
+ if (log_domain.size() && label.size())
+ str += "-";
+ str += label;
+ if (ident.size())
+ {
+ if (log_domain.size() || label.size())
+ str += "(" + ident + ")";
+ else
+ str += ident;
+ }
+ /* more components can come here */
+ /* ... */
+ return str;
+}
+
+static DataKey<Msg::Handler> msg_thread_handler_key;
+
+/**
+ * @param handler a valid Msg::Handler or NULL
+ *
+ * Set the handler function for messages logged in the current
+ * thread. If NULL is specified as handler, the standard handler
+ * will be used. For handler implementations that require an extra
+ * data argument, see Thread::set_data().
+ * This function is MT-safe and may be called from any thread.
+ */
+void
+Msg::set_thread_handler (Handler handler)
+{
+ Thread &self = Thread::self();
+ self.set_data (&msg_thread_handler_key, handler);
+}
+
+void
+Msg::display_parts (const char *domain,
+ Type message_type,
+ const vector<Part> &parts)
+{
+ int saved_errno = errno;
+ String title, primary, secondary, details, checkmsg;
+ for (uint i = 0; i < parts.size(); i++)
+ switch (parts[i].ptype)
+ {
+ case '0': title += (title.size() ? "\n" : "") + parts[i].string; break;
+ case '1': primary += (primary.size() ? "\n" : "") + parts[i].string; break;
+ case '2': secondary += (secondary.size() ? "\n" : "") + parts[i].string; break;
+ case '3': details += (details.size() ? "\n" : "") + parts[i].string; break;
+ case 'c': checkmsg += (checkmsg.size() ? "\n" : "") + parts[i].string; break;
+ }
+ String ident = type_ident (message_type);
+ uint32 actions = type_flags (message_type);
+ /* log to stderr */
+ bool tostderr = (actions & LOG_TO_STDERR) || (msg_log_to_stderr && (actions & LOG_TO_STDLOG));
+ if (tostderr && (primary.size() || secondary.size()))
+ {
+ bool is_debug = message_type == DEBUG, is_diag = message_type == DIAG;
+ String label = type_label (message_type);
+ String prefix = log_prefix (prgname (is_debug), /* strip prgname path for debugging */
+ Thread::Self::pid(), /* always print pid */
+ is_debug ? "" : domain, /* print domain except when debugging */
+ is_debug || is_diag ? "" : label, /* print translated message type execpt for debug/diagnosis */
+ is_debug ? ident : ""); /* print identifier if debugging */
+ if (title.size())
+ fprintf (stderr, "%s:0: %s\n", prefix.c_str(), title.c_str());
+ if (primary.size())
+ fprintf (stderr, "%s:1: %s\n", prefix.c_str(), primary.c_str());
+ if (secondary.size())
+ fprintf (stderr, "%s:2: %s\n", prefix.c_str(), secondary.c_str());
+ if (details.size())
+ fprintf (stderr, "%s:3: %s\n", prefix.c_str(), details.c_str());
+ if (0 && checkmsg.size())
+ fprintf (stderr, "%s:c: %s\n", prefix.c_str(), checkmsg.c_str());
+ }
+ /* log to syslog */
+ if (msg_syslog_priority && (primary.size() || secondary.size()) && (actions & LOG_TO_STDLOG))
+ {
+ String prefix = log_prefix ("", 0, domain, "", ident);
+ if (title.size() && false) // skip title in syslog
+ syslog (msg_syslog_priority, "%s:0: %s\n", prefix.c_str(), title.c_str());
+ if (primary.size())
+ syslog (msg_syslog_priority, "%s:1: %s\n", prefix.c_str(), primary.c_str());
+ if (secondary.size())
+ syslog (msg_syslog_priority, "%s:2: %s\n", prefix.c_str(), secondary.c_str());
+ if (details.size() && false) // skip details in syslog
+ syslog (msg_syslog_priority, "%s:3: %s\n", prefix.c_str(), details.c_str());
+ }
+ /* log to logfile */
+ if (msg_log_file && (actions & LOG_TO_STDLOG))
+ {
+ String prefix = log_prefix (prgname (false), /* printf fully qualified program name */
+ Thread::Self::pid(), /* always print pid */
+ domain, /* always print log domain */
+ "", /* skip translated message type */
+ ident); /* print machine readable message type */
+ if (title.size())
+ fprintf (msg_log_file, "%s:0: %s\n", prefix.c_str(), title.c_str());
+ if (primary.size())
+ fprintf (msg_log_file, "%s:1: %s\n", prefix.c_str(), primary.c_str());
+ if (secondary.size())
+ fprintf (msg_log_file, "%s:2: %s\n", prefix.c_str(), secondary.c_str());
+ if (details.size())
+ fprintf (msg_log_file, "%s:3: %s\n", prefix.c_str(), details.c_str());
+ }
+ /* log to log handler */
+ if (actions & LOG_TO_HANDLER)
+ {
+ Thread &self = Thread::self();
+ Handler log_handler = self.get_data (&msg_thread_handler_key);
+ if (!log_handler)
+ log_handler = default_handler;
+ log_handler (domain, message_type, parts);
+ }
+ errno = saved_errno;
+}
+
+void
+Msg::display_aparts (Type message_type,
+ const Part &p0, const Part &p1,
+ const Part &p2, const Part &p3,
+ const Part &p4, const Part &p5,
+ const Part &p6, const Part &p7,
+ const Part &p8, const Part &p9)
+{
+ int saved_errno = errno;
+ vector<Part> parts;
+ parts.push_back (p0);
+ parts.push_back (p1);
+ parts.push_back (p2);
+ parts.push_back (p3);
+ parts.push_back (p4);
+ parts.push_back (p5);
+ parts.push_back (p6);
+ parts.push_back (p7);
+ parts.push_back (p8);
+ parts.push_back (p9);
+ display_parts (BIRNET_LOG_DOMAIN, message_type, parts);
+ errno = saved_errno;
+}
+
+/**
+ * @param domain message domain
+ * @param parts message parts
+ *
+ * This is the standard message handler, it produces @a message
+ * in a prominent way on stderr.
+ * This function is MT-safe and may be called from any thread.
+ */
+void
+Msg::default_handler (const char *domain,
+ Type mtype,
+ const vector<Part> &parts)
+{
+ String level_name = type_label (mtype);
+ String title, primary, secondary, details, checkmsg;
+ for (uint i = 0; i < parts.size(); i++)
+ switch (parts[i].ptype)
+ {
+ case '0': title += (title.size() ? "\n" : "") + parts[i].string; break;
+ case '1': primary += (primary.size() ? "\n" : "") + parts[i].string; break;
+ case '2': secondary += (secondary.size() ? "\n" : "") + parts[i].string; break;
+ case '3': details += (details.size() ? "\n" : "") + parts[i].string; break;
+ case 'c': checkmsg += (checkmsg.size() ? "\n" : "") + parts[i].string; break;
+ }
+ g_printerr ("********************************************************************************\n");
+ if (domain)
+ g_printerr ("** %s-%s: %s\n", domain, level_name.c_str(), title.c_str());
+ else
+ g_printerr ("** %s: %s\n", level_name.c_str(), title.c_str());
+ if (primary.size())
+ g_printerr ("** %s\n", primary.c_str());
+ if (secondary.size())
+ {
+ String str = secondary;
+ for (uint i = 0; i < str.size(); i++)
+ if (str[i] == '\n')
+ str.insert (i + 1, "** ");
+ g_printerr ("** %s\n", str.c_str());
+ }
+ if (details.size())
+ {
+ String str = details;
+ for (uint i = 0; i < str.size(); i++)
+ if (str[i] == '\n')
+ str.insert (i + 1, "** > ");
+ g_printerr ("** > %s\n", str.c_str());
+ }
+ if (checkmsg.size())
+ g_printerr ("** [X] %s\n", checkmsg.c_str());
+ g_printerr ("********************************************************************************\n");
+}
+
} // Birnet
Modified: trunk/birnet/birnetmsg.hh
===================================================================
--- trunk/birnet/birnetmsg.hh 2006-11-15 15:08:43 UTC (rev 4085)
+++ trunk/birnet/birnetmsg.hh 2006-11-21 00:13:13 UTC (rev 4086)
@@ -26,12 +26,53 @@
/* --- messaging --- */
struct Msg {
+ /* message parts */
+ struct Part; /* base for Text* and Check */
+ struct Text0; typedef Text0 Title; /* message title */
+ struct Text1; typedef Text1 Primary; /* primary message */
+ struct Text2; typedef Text2 Secondary; /* secondary message (lengthy) */
+ struct Text3; typedef Text3 Detail; /* message details */
+ struct Check; /* enable/disable message text */
typedef enum {
- ERROR = 'E',
- WARNING = 'W',
- INFO = 'I',
- DEBUG = 'D',
+ LOG_TO_STDERR = 1,
+ LOG_TO_STDLOG = 2,
+ LOG_TO_HANDLER = 4,
+ _1FORCE32 = 0xf000000
+ } LogFlags;
+ /* message types */
+ typedef enum {
+ NONE = 0, /* always off */
+ ALWAYS = 1, /* always on */
+ ERROR, WARNING, SCRIPT,
+ INFO, DIAG, DEBUG,
+ _2FORCE32 = 0xf000000
} Type;
+ static Type register_type (const char *ident,
+ Type default_ouput,
+ const char *label);
+ static Type lookup_type (const String &ident);
+ static const char* type_ident (Type mtype);
+ static const char* type_label (Type mtype);
+ static uint32 type_flags (Type mtype);
+ static inline bool check (Type mtype);
+ static void enable (Type mtype);
+ static void disable (Type mtype);
+ static void configure (Type mtype,
+ LogFlags log_mask,
+ const String &logfile);
+ static void allow_msgs (const String &key);
+ static void deny_msgs (const String &key);
+ static void configure_stdlog (bool redirect_stdlog_to_stderr,
+ const String &stdlog_filename,
+ uint syslog_priority);
+ /* messaging */
+ static inline void display (Type message_type,
+ const Part &p0 = empty_part, const Part &p1 = empty_part,
+ const Part &p2 = empty_part, const Part &p3 = empty_part,
+ const Part &p4 = empty_part, const Part &p5 = empty_part,
+ const Part &p6 = empty_part, const Part &p7 = empty_part,
+ const Part &p8 = empty_part, const Part &p9 = empty_part);
+ /* message handling */
struct Part {
String string;
uint8 ptype;
@@ -44,6 +85,35 @@
const char *format,
va_list varargs);
};
+ typedef void (*Handler) (const char *domain,
+ Type mtype,
+ const vector<Part> &parts);
+ static void set_thread_handler (Handler handler);
+ static void default_handler (const char *domain,
+ Type mtype,
+ const vector<Part> &parts);
+ static void display_parts (const char *domain,
+ Type message_type,
+ const vector<Part> &parts);
+protected:
+ static const Part &empty_part;
+ static void display_aparts (Type message_type,
+ const Part &p0, const Part &p1,
+ const Part &p2, const Part &p3,
+ const Part &p4, const Part &p5,
+ const Part &p6, const Part &p7,
+ const Part &p8, const Part &p9);
+ BIRNET_PRIVATE_CLASS_COPY (Msg);
+private:
+ static volatile int n_msg_types;
+ static uint8 *volatile msg_type_bits;
+ static void init_standard_types ();
+ static void key_list_change_L (const String &keylist,
+ bool isenabled);
+ static void set_msg_type_L (uint mtype,
+ uint32 flags,
+ bool enabled);
+public:
struct Text0 : public Part { /* message title */
explicit BIRNET_PRINTF (2, 3) Text0 (const char *format, ...) { va_list a; va_start (a, format); setup ('0', format, a); va_end (a); }
explicit Text0 (const String &s) { setup ('0', s); }
@@ -64,40 +134,33 @@
explicit BIRNET_PRINTF (2, 3) Check (const char *format, ...) { va_list a; va_start (a, format); setup ('c', format, a); va_end (a); }
explicit Check (const String &s) { setup ('c', s); }
};
- typedef Text0 Title; /* message title */
- typedef Text1 Primary; /* primary message */
- typedef Text2 Secondary; /* secondary message (lengthy) */
- typedef Text3 Detail; /* message details */
- static inline void display (Type message_type,
- const Part &p0 = empty_part,
- const Part &p1 = empty_part,
- const Part &p2 = empty_part,
- const Part &p3 = empty_part,
- const Part &p4 = empty_part);
-protected:
- static const Part &empty_part;
- static void display (const char *domain,
- const vector<Part> &parts);
- /* FIXME: allow installing of handler for vector<Part&> */
- BIRNET_PRIVATE_CLASS_COPY (Msg);
+ struct Custom : public Part { /* custom part / user defined */
+ explicit BIRNET_PRINTF (3, 4) Custom (uint8 ctype, const char *format, ...) { va_list a; va_start (a, format); setup (ctype | 0x80, format, a); va_end (a); }
+ explicit Custom (uint8 ctype, const String &s) { setup (ctype | 0x80, s); }
+ };
};
-/* --- inline implementation --- */
+/* --- inline implementations --- */
+inline bool
+Msg::check (Type mtype)
+{
+ /* this function is supposed to preserve errno */
+ return (mtype >= 0 &&
+ mtype < n_msg_types &&
+ (msg_type_bits[mtype / 8] & (1 << mtype % 8)));
+}
+
inline void
Msg::display (Type message_type,
- const Part &p0,
- const Part &p1,
- const Part &p2,
- const Part &p3,
- const Part &p4)
+ const Part &p0, const Part &p1,
+ const Part &p2, const Part &p3,
+ const Part &p4, const Part &p5,
+ const Part &p6, const Part &p7,
+ const Part &p8, const Part &p9)
{
- vector<Part> parts;
- parts.push_back (p0);
- parts.push_back (p1);
- parts.push_back (p2);
- parts.push_back (p3);
- parts.push_back (p4);
- display (BIRNET_LOG_DOMAIN, parts);
+ /* this function is supposed to preserve errno */
+ if (check (message_type))
+ display_aparts (message_type, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
} // Birnet
Modified: trunk/birnet/birnetthread.cc
===================================================================
--- trunk/birnet/birnetthread.cc 2006-11-15 15:08:43 UTC (rev 4085)
+++ trunk/birnet/birnetthread.cc 2006-11-21 00:13:13 UTC (rev 4086)
@@ -257,7 +257,10 @@
ThreadTable.thread_exit (retval);
}
-Mutex::Mutex ()
+static const BirnetMutex zero_mutex = { 0, };
+
+Mutex::Mutex () :
+ mutex (zero_mutex)
{
if (birnet_threads_initialized())
ThreadTable.mutex_init (&mutex);
@@ -273,7 +276,10 @@
ThreadTable.mutex_unchain (&mutex);
}
-RecMutex::RecMutex ()
+static const BirnetRecMutex zero_rec_mutex = { { 0, }, };
+
+RecMutex::RecMutex () :
+ rmutex (zero_rec_mutex)
{
if (birnet_threads_initialized())
ThreadTable.rec_mutex_init (&rmutex);
@@ -289,7 +295,10 @@
ThreadTable.rec_mutex_unchain (&rmutex);
}
-Cond::Cond ()
+static const BirnetCond zero_cond = { 0, };
+
+Cond::Cond () :
+ cond (zero_cond)
{
if (birnet_threads_initialized())
ThreadTable.cond_init (&cond);
@@ -306,6 +315,7 @@
}
OwnedMutex::OwnedMutex () :
+ m_rec_mutex (zero_rec_mutex),
m_owner (NULL)
{
if (birnet_threads_initialized())
Modified: trunk/birnet/tests/infotest.cc
===================================================================
--- trunk/birnet/tests/infotest.cc 2006-11-15 15:08:43 UTC (rev 4085)
+++ trunk/birnet/tests/infotest.cc 2006-11-21 00:13:13 UTC (rev 4086)
@@ -103,6 +103,40 @@
}
static void
+test_messaging ()
+{
+ TSTART ("Message Types");
+ TASSERT (Msg::NONE == Msg::lookup_type ("none"));
+ TASSERT (Msg::ALWAYS == Msg::lookup_type ("always"));
+ TASSERT (Msg::ERROR == Msg::lookup_type ("error"));
+ TASSERT (Msg::WARNING == Msg::lookup_type ("warning"));
+ TASSERT (Msg::SCRIPT == Msg::lookup_type ("script"));
+ TASSERT (Msg::INFO == Msg::lookup_type ("info"));
+ TASSERT (Msg::DIAG == Msg::lookup_type ("diag"));
+ TASSERT (Msg::DEBUG == Msg::lookup_type ("debug"));
+ TASSERT (Msg::check (Msg::NONE) == false);
+ TASSERT (Msg::check (Msg::ALWAYS) == true);
+ Msg::enable (Msg::NONE);
+ Msg::disable (Msg::ALWAYS);
+ TASSERT (Msg::check (Msg::NONE) == false);
+ TASSERT (Msg::check (Msg::ALWAYS) == true);
+ TASSERT (Msg::check (Msg::INFO) == true);
+ Msg::disable (Msg::INFO);
+ TASSERT (Msg::check (Msg::INFO) == false);
+ Msg::enable (Msg::INFO);
+ TASSERT (Msg::check (Msg::INFO) == true);
+ TDONE();
+ Msg::display (Msg::WARNING,
+ Msg::Title ("Warning Title"),
+ Msg::Text1 ("Primary warning message."),
+ Msg::Text2 ("Secondary warning message."),
+ Msg::Text2 ("Continuation of secondary warning message."),
+ Msg::Text3 ("Message details: 1, 2, 3."),
+ Msg::Text3 ("And more message details: a, b, c."),
+ Msg::Check ("Show this message again."));
+}
+
+static void
test_virtual_typeid()
{
struct TypeA : public virtual VirtualTypeid {};
@@ -127,6 +161,7 @@
test_paths();
test_zintern();
test_files (argv[0]);
+ test_messaging();
test_virtual_typeid();
return 0;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]