egl: add copyright notices
[mesa.git] / src / egl / main / egllog.c
index 1d7a0a388c6923c88cacf782833b47c1944ccf9d..43eed64c2992b2897d4a2fff34590587a425ff8f 100644 (file)
@@ -1,3 +1,33 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright 2010 LunarG, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
 /**
  * Logging facility for debug/info messages.
  * _EGL_FATAL messages are printed to stderr
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+
 #include "egllog.h"
+#include "eglstring.h"
+#include "eglmutex.h"
 
 #define MAXSTRING 1000
-#define FALLBACK_LOG_LEVEL      _EGL_WARNING
-#define FALLBACK_LOG_LEVEL_STR  "warning"
+#define FALLBACK_LOG_LEVEL _EGL_WARNING
 
-static EGLint ReportingLevel = -1;
 
+static struct {
+   _EGLMutex mutex;
 
-static void
-log_level_initialize(void)
+   EGLBoolean initialized;
+   EGLint level;
+   _EGLLogProc logger;
+   EGLint num_messages;
+} logging = {
+   _EGL_MUTEX_INITIALIZER,
+   EGL_FALSE,
+   FALLBACK_LOG_LEVEL,
+   NULL,
+   0
+};
+
+static const char *level_strings[] = {
+   /* the order is important */
+   "fatal",
+   "warning",
+   "info",
+   "debug",
+   NULL
+};
+
+
+/**
+ * Set the function to be called when there is a message to log.
+ * Note that the function will be called with an internal lock held.
+ * Recursive logging is not allowed.
+ */
+void
+_eglSetLogProc(_EGLLogProc logger)
 {
-#if defined(_EGL_PLATFORM_X)  
-   char *log_env = getenv("EGL_LOG_LEVEL");
-#else
-   char *log_env = NULL;
-#endif
-
-   if (log_env == NULL) {
-      ReportingLevel = FALLBACK_LOG_LEVEL;
-   }
-   else if (strcasecmp(log_env, "fatal") == 0) {
-      ReportingLevel = _EGL_FATAL;
-   }
-   else if (strcasecmp(log_env, "warning") == 0) {
-      ReportingLevel = _EGL_WARNING;
+   EGLint num_messages = 0;
+
+   _eglLockMutex(&logging.mutex);
+
+   if (logging.logger != logger) {
+      logging.logger = logger;
+
+      num_messages = logging.num_messages;
+      logging.num_messages = 0;
    }
-   else if (strcasecmp(log_env, "info") == 0) {
-      ReportingLevel = _EGL_INFO;
+
+   _eglUnlockMutex(&logging.mutex);
+
+   if (num_messages)
+      _eglLog(_EGL_DEBUG,
+              "New logger installed. "
+              "Messages before the new logger might not be available.");
+}
+
+
+/**
+ * Set the log reporting level.
+ */
+void
+_eglSetLogLevel(EGLint level)
+{
+   switch (level) {
+   case _EGL_FATAL:
+   case _EGL_WARNING:
+   case _EGL_INFO:
+   case _EGL_DEBUG:
+      _eglLockMutex(&logging.mutex);
+      logging.level = level;
+      _eglUnlockMutex(&logging.mutex);
+      break;
+   default:
+      break;
    }
-   else if (strcasecmp(log_env, "debug") == 0) {
-      ReportingLevel = _EGL_DEBUG;
+}
+
+
+/**
+ * The default logger.  It prints the message to stderr.
+ */
+static void
+_eglDefaultLogger(EGLint level, const char *msg)
+{
+   fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg);
+}
+
+
+/**
+ * Initialize the logging facility.
+ */
+static void
+_eglInitLogger(void)
+{
+   const char *log_env;
+   EGLint i, level = -1;
+
+   if (logging.initialized)
+      return;
+
+   log_env = getenv("EGL_LOG_LEVEL");
+   if (log_env) {
+      for (i = 0; level_strings[i]; i++) {
+         if (_eglstrcasecmp(log_env, level_strings[i]) == 0) {
+            level = i;
+            break;
+         }
+      }
    }
    else {
-      fprintf(stderr, "Unrecognized EGL_LOG_LEVEL environment variable value. "
+      level = FALLBACK_LOG_LEVEL;
+   }
+
+   logging.logger = _eglDefaultLogger;
+   logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
+   logging.initialized = EGL_TRUE;
+
+   /* it is fine to call _eglLog now */
+   if (log_env && level < 0) {
+      _eglLog(_EGL_WARNING,
+              "Unrecognized EGL_LOG_LEVEL environment variable value. "
               "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
-              "Got \"%s\". Falling back to \"%s\".\n",
-              log_env, FALLBACK_LOG_LEVEL_STR);
-      ReportingLevel = FALLBACK_LOG_LEVEL;
+              "Got \"%s\". Falling back to \"%s\".",
+              log_env, level_strings[FALLBACK_LOG_LEVEL]);
    }
 }
 
 
 /**
- * Log a message to stderr.
+ * Log a message with message logger.
  * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
  */
 void
@@ -61,40 +181,29 @@ _eglLog(EGLint level, const char *fmtStr, ...)
 {
    va_list args;
    char msg[MAXSTRING];
-   const char *levelStr;
-   static int log_level_initialized = 0;
+   int ret;
 
-   if (!log_level_initialized) {
-      log_level_initialize();
-      log_level_initialized = 1;
-   }
+   /* one-time initialization; a little race here is fine */
+   if (!logging.initialized)
+      _eglInitLogger();
+   if (level > logging.level || level < 0)
+      return;
 
-   if (level <= ReportingLevel) {
-      switch (level) {
-      case _EGL_FATAL:
-         levelStr = "Fatal";
-         break;
-      case _EGL_WARNING:
-         levelStr = "Warning";
-         break;
-      case _EGL_INFO:
-         levelStr = "Info";
-         break;
-      case _EGL_DEBUG:
-         levelStr = "Debug";
-         break;
-      default:
-         levelStr = "";
-      }
+   _eglLockMutex(&logging.mutex);
 
+   if (logging.logger) {
       va_start(args, fmtStr);
-      vsnprintf(msg, MAXSTRING, fmtStr, args);
+      ret = vsnprintf(msg, MAXSTRING, fmtStr, args);
+      if (ret < 0 || ret >= MAXSTRING)
+         strcpy(msg, "<message truncated>");
       va_end(args);
 
-      fprintf(stderr, "libEGL %s: %s\n", levelStr, msg);
-
-      if (level == _EGL_FATAL) {
-         exit(1); /* or abort()? */
-      }
+      logging.logger(level, msg);
+      logging.num_messages++;
    }
+
+   _eglUnlockMutex(&logging.mutex);
+
+   if (level == _EGL_FATAL)
+      exit(1); /* or abort()? */
 }