Main Page | Class List | Directories | File List | Class Members | File Members

gmessages.c

Go to the documentation of this file.
00001 /* GLIB - Library of useful routines for C programming
00002  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 /*
00021  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
00022  * file for a list of people on the GLib Team.  See the ChangeLog
00023  * files for a list of changes.  These files are distributed with
00024  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
00025  */
00026 
00027 /* 
00028  * MT safe
00029  */
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034 
00035 #include <stdlib.h>
00036 #include <stdarg.h>
00037 #include <stdio.h>
00038 #include <string.h>
00039 #include "glib.h"
00040 #ifdef HAVE_UNISTD_H
00041 #include <unistd.h>
00042 #endif
00043 
00044 #ifdef NATIVE_WIN32
00045 #define STRICT
00046 #include <windows.h>
00047 
00048 /* Just use stdio. If we're out of memory, we're hosed anyway. */
00049 #undef write
00050 
00051 static inline int
00052 write (FILE       *fd,
00053        const char *buf,
00054        int         len)
00055 {
00056   fwrite (buf, len, 1, fd);
00057 
00058   return len;
00059 }
00060 
00061 static void
00062 ensure_stdout_valid (void)
00063 {
00064   HANDLE handle;
00065 
00066   handle = GetStdHandle (STD_OUTPUT_HANDLE);
00067   
00068   if (handle == INVALID_HANDLE_VALUE)
00069     {
00070       AllocConsole ();
00071       freopen ("CONOUT$", "w", stdout);
00072     }
00073 }
00074 #else
00075 #define ensure_stdout_valid()   /* Define as empty */
00076 #endif
00077         
00078 
00079 /* --- structures --- */
00080 typedef struct _GLogDomain      GLogDomain;
00081 typedef struct _GLogHandler     GLogHandler;
00082 struct _GLogDomain
00083 {
00084   gchar         *log_domain;
00085   GLogLevelFlags fatal_mask;
00086   GLogHandler   *handlers;
00087   GLogDomain    *next;
00088 };
00089 struct _GLogHandler
00090 {
00091   guint          id;
00092   GLogLevelFlags log_level;
00093   GLogFunc       log_func;
00094   gpointer       data;
00095   GLogHandler   *next;
00096 };
00097 
00098 
00099 /* --- variables --- */
00100 
00101 static GMutex* g_messages_lock = NULL;
00102 
00103 const gchar          *g_log_domain_glib = "GLib";
00104 static GLogDomain    *g_log_domains = NULL;
00105 static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
00106 static GPrintFunc     glib_print_func = NULL;
00107 static GPrintFunc     glib_printerr_func = NULL;
00108 static GErrorFunc     glib_error_func = NULL;
00109 static GWarningFunc   glib_warning_func = NULL;
00110 static GPrintFunc     glib_message_func = NULL;
00111 
00112 static GPrivate* g_log_depth = NULL;
00113 
00114 
00115 /* --- functions --- */
00116 static inline GLogDomain*
00117 g_log_find_domain (const gchar    *log_domain)
00118 {
00119   register GLogDomain *domain;
00120   
00121   g_mutex_lock (g_messages_lock);
00122   domain = g_log_domains;
00123   while (domain)
00124     {
00125       if (strcmp (domain->log_domain, log_domain) == 0)
00126         {
00127           g_mutex_unlock (g_messages_lock);
00128           return domain;
00129         }
00130       domain = domain->next;
00131     }
00132   g_mutex_unlock (g_messages_lock);
00133   return NULL;
00134 }
00135 
00136 static inline GLogDomain*
00137 g_log_domain_new (const gchar *log_domain)
00138 {
00139   register GLogDomain *domain;
00140 
00141   domain = g_new (GLogDomain, 1);
00142   domain->log_domain = g_strdup (log_domain);
00143   domain->fatal_mask = G_LOG_FATAL_MASK;
00144   domain->handlers = NULL;
00145   
00146   g_mutex_lock (g_messages_lock);
00147   domain->next = g_log_domains;
00148   g_log_domains = domain;
00149   g_mutex_unlock (g_messages_lock);
00150   
00151   return domain;
00152 }
00153 
00154 static inline void
00155 g_log_domain_check_free (GLogDomain *domain)
00156 {
00157   if (domain->fatal_mask == G_LOG_FATAL_MASK &&
00158       domain->handlers == NULL)
00159     {
00160       register GLogDomain *last, *work;
00161       
00162       last = NULL;  
00163 
00164       g_mutex_lock (g_messages_lock);
00165       work = g_log_domains;
00166       while (work)
00167         {
00168           if (work == domain)
00169             {
00170               if (last)
00171                 last->next = domain->next;
00172               else
00173                 g_log_domains = domain->next;
00174               g_free (domain->log_domain);
00175               g_free (domain);
00176               break;
00177             }
00178           last = work;
00179           work = last->next;
00180         }  
00181       g_mutex_unlock (g_messages_lock);
00182     }
00183 }
00184 
00185 static inline GLogFunc
00186 g_log_domain_get_handler (GLogDomain    *domain,
00187                           GLogLevelFlags log_level,
00188                           gpointer      *data)
00189 {
00190   if (domain && log_level)
00191     {
00192       register GLogHandler *handler;
00193       
00194       handler = domain->handlers;
00195       while (handler)
00196         {
00197           if ((handler->log_level & log_level) == log_level)
00198             {
00199               *data = handler->data;
00200               return handler->log_func;
00201             }
00202           handler = handler->next;
00203         }
00204     }
00205   return g_log_default_handler;
00206 }
00207 
00208 GLogLevelFlags
00209 g_log_set_always_fatal (GLogLevelFlags fatal_mask)
00210 {
00211   GLogLevelFlags old_mask;
00212 
00213   /* restrict the global mask to levels that are known to glib */
00214   fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
00215   /* force errors to be fatal */
00216   fatal_mask |= G_LOG_LEVEL_ERROR;
00217   /* remove bogus flag */
00218   fatal_mask &= ~G_LOG_FLAG_FATAL;
00219 
00220   g_mutex_lock (g_messages_lock);
00221   old_mask = g_log_always_fatal;
00222   g_log_always_fatal = fatal_mask;
00223   g_mutex_unlock (g_messages_lock);
00224 
00225   return old_mask;
00226 }
00227 
00228 GLogLevelFlags
00229 g_log_set_fatal_mask (const gchar    *log_domain,
00230                       GLogLevelFlags  fatal_mask)
00231 {
00232   GLogLevelFlags old_flags;
00233   register GLogDomain *domain;
00234   
00235   if (!log_domain)
00236     log_domain = "";
00237   
00238   /* force errors to be fatal */
00239   fatal_mask |= G_LOG_LEVEL_ERROR;
00240   /* remove bogus flag */
00241   fatal_mask &= ~G_LOG_FLAG_FATAL;
00242   
00243   domain = g_log_find_domain (log_domain);
00244   if (!domain)
00245     domain = g_log_domain_new (log_domain);
00246   old_flags = domain->fatal_mask;
00247   
00248   domain->fatal_mask = fatal_mask;
00249   g_log_domain_check_free (domain);
00250   
00251   return old_flags;
00252 }
00253 
00254 guint
00255 g_log_set_handler (const gchar    *log_domain,
00256                    GLogLevelFlags  log_levels,
00257                    GLogFunc        log_func,
00258                    gpointer        user_data)
00259 {
00260   register GLogDomain *domain;
00261   register GLogHandler *handler;
00262   static guint handler_id = 0;
00263   
00264   g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
00265   g_return_val_if_fail (log_func != NULL, 0);
00266   
00267   if (!log_domain)
00268     log_domain = "";
00269   
00270   domain = g_log_find_domain (log_domain);
00271   if (!domain)
00272     domain = g_log_domain_new (log_domain);
00273   
00274   handler = g_new (GLogHandler, 1);
00275   g_mutex_lock (g_messages_lock);
00276   handler->id = ++handler_id;
00277   g_mutex_unlock (g_messages_lock);
00278   handler->log_level = log_levels;
00279   handler->log_func = log_func;
00280   handler->data = user_data;
00281   handler->next = domain->handlers;
00282   domain->handlers = handler;
00283   
00284   return handler_id;
00285 }
00286 
00287 void
00288 g_log_remove_handler (const gchar    *log_domain,
00289                       guint           handler_id)
00290 {
00291   register GLogDomain *domain;
00292   
00293   g_return_if_fail (handler_id > 0);
00294   
00295   if (!log_domain)
00296     log_domain = "";
00297   
00298   domain = g_log_find_domain (log_domain);
00299   if (domain)
00300     {
00301       register GLogHandler *work, *last;
00302       
00303       last = NULL;
00304       work = domain->handlers;
00305       while (work)
00306         {
00307           if (work->id == handler_id)
00308             {
00309               if (last)
00310                 last->next = work->next;
00311               else
00312                 domain->handlers = work->next;
00313               g_free (work);
00314               g_log_domain_check_free (domain);
00315               return;
00316             }
00317           last = work;
00318           work = last->next;
00319         }
00320     }
00321   g_warning ("g_log_remove_handler(): could not find handler with id `%d' for domain \"%s\"",
00322              handler_id,
00323              log_domain);
00324 }
00325 
00326 void
00327 g_logv (const gchar    *log_domain,
00328         GLogLevelFlags  log_level,
00329         const gchar    *format,
00330         va_list         args1)
00331 {
00332   va_list args2;
00333   gchar buffer[1025];
00334   register gint i;
00335   
00336   log_level &= G_LOG_LEVEL_MASK;
00337   if (!log_level)
00338     return;
00339   
00340   /* we use a stack buffer of fixed size, because we might get called
00341    * recursively.
00342    */
00343   G_VA_COPY (args2, args1);
00344   if (g_printf_string_upper_bound (format, args1) < 1024)
00345     vsprintf (buffer, format, args2);
00346   else
00347     {
00348       /* since we might be out of memory, we can't use g_vsnprintf(). */
00349 #ifdef  HAVE_VSNPRINTF
00350       vsnprintf (buffer, 1024, format, args2);
00351 #else   /* !HAVE_VSNPRINTF */
00352       /* we are out of luck here */
00353       strncpy (buffer, format, 1024);
00354 #endif  /* !HAVE_VSNPRINTF */
00355       buffer[1024] = 0;
00356     }
00357   va_end (args2);
00358   
00359   for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
00360     {
00361       register GLogLevelFlags test_level;
00362       
00363       test_level = 1 << i;
00364       if (log_level & test_level)
00365         {
00366           guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
00367           GLogDomain *domain;
00368           GLogFunc log_func;
00369           gpointer data = NULL;
00370           
00371           domain = g_log_find_domain (log_domain ? log_domain : "");
00372           
00373           if (depth)
00374             test_level |= G_LOG_FLAG_RECURSION;
00375           
00376           depth++;
00377           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
00378 
00379           g_mutex_lock (g_messages_lock);
00380           if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | 
00381                 g_log_always_fatal) & test_level) != 0)
00382             test_level |= G_LOG_FLAG_FATAL;  
00383           g_mutex_unlock (g_messages_lock);
00384 
00385           log_func = g_log_domain_get_handler (domain, test_level, &data);
00386           log_func (log_domain, test_level, buffer, data);
00387           
00388           /* *domain can be cluttered now */
00389           
00390           if (test_level & G_LOG_FLAG_FATAL)
00391             abort ();
00392           
00393           depth--;
00394           g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
00395         }
00396     }
00397 }
00398 
00399 void
00400 g_log (const gchar    *log_domain,
00401        GLogLevelFlags  log_level,
00402        const gchar    *format,
00403        ...)
00404 {
00405   va_list args;
00406   
00407   va_start (args, format);
00408   g_logv (log_domain, log_level, format, args);
00409   va_end (args);
00410 }
00411 
00412 void
00413 g_log_default_handler (const gchar    *log_domain,
00414                        GLogLevelFlags  log_level,
00415                        const gchar    *message,
00416                        gpointer        unused_data)
00417 {
00418 #ifdef NATIVE_WIN32
00419   FILE *fd;
00420 #else
00421   gint fd;
00422 #endif
00423   gboolean in_recursion;
00424   gboolean is_fatal;  
00425   GErrorFunc     local_glib_error_func;
00426   GWarningFunc   local_glib_warning_func;
00427   GPrintFunc     local_glib_message_func;
00428 
00429   in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
00430   is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
00431   log_level &= G_LOG_LEVEL_MASK;
00432   
00433   if (!message)
00434     message = "g_log_default_handler(): (NULL) message";
00435   
00436 #ifdef NATIVE_WIN32
00437   /* Use just stdout as stderr is hard to get redirected from the
00438    * DOS prompt.
00439    */
00440   fd = stdout;
00441 #else
00442   fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
00443 #endif
00444   
00445   g_mutex_lock (g_messages_lock);
00446   local_glib_error_func = glib_error_func;
00447   local_glib_warning_func = glib_warning_func;
00448   local_glib_message_func = glib_message_func;
00449   g_mutex_unlock (g_messages_lock);
00450 
00451   switch (log_level)
00452     {
00453     case G_LOG_LEVEL_ERROR:
00454       if (!log_domain && local_glib_error_func)
00455         {
00456           /* compatibility code */
00457           local_glib_error_func (message);  
00458           return;
00459         }
00460       /* use write(2) for output, in case we are out of memeory */
00461       ensure_stdout_valid ();
00462       if (log_domain)
00463         {
00464           write (fd, "\n", 1);
00465           write (fd, log_domain, strlen (log_domain));
00466           write (fd, "-", 1);
00467         }
00468       else
00469         write (fd, "\n** ", 4);
00470       if (in_recursion)
00471         write (fd, "ERROR (recursed) **: ", 21);
00472       else
00473         write (fd, "ERROR **: ", 10);
00474       write (fd, message, strlen(message));
00475       if (is_fatal)
00476         write (fd, "\naborting...\n", 13);
00477       else
00478         write (fd, "\n", 1);
00479       break;
00480     case G_LOG_LEVEL_CRITICAL:
00481       ensure_stdout_valid ();
00482       if (log_domain)
00483         {
00484           write (fd, "\n", 1);
00485           write (fd, log_domain, strlen (log_domain));
00486           write (fd, "-", 1);
00487         }
00488       else
00489         write (fd, "\n** ", 4);
00490       if (in_recursion)
00491         write (fd, "CRITICAL (recursed) **: ", 24);
00492       else
00493         write (fd, "CRITICAL **: ", 13);
00494       write (fd, message, strlen(message));
00495       if (is_fatal)
00496         write (fd, "\naborting...\n", 13);
00497       else
00498         write (fd, "\n", 1);
00499       break;
00500     case G_LOG_LEVEL_WARNING:
00501       if (!log_domain && local_glib_warning_func)
00502         {
00503           /* compatibility code */
00504           local_glib_warning_func (message);
00505           return;
00506         }
00507       ensure_stdout_valid ();
00508       if (log_domain)
00509         {
00510           write (fd, "\n", 1);
00511           write (fd, log_domain, strlen (log_domain));
00512           write (fd, "-", 1);
00513         }
00514       else
00515         write (fd, "\n** ", 4);
00516       if (in_recursion)
00517         write (fd, "WARNING (recursed) **: ", 23);
00518       else
00519         write (fd, "WARNING **: ", 12);
00520       write (fd, message, strlen(message));
00521       if (is_fatal)
00522         write (fd, "\naborting...\n", 13);
00523       else
00524         write (fd, "\n", 1);
00525       break;
00526     case G_LOG_LEVEL_MESSAGE:
00527       if (!log_domain && local_glib_message_func)
00528         {
00529           /* compatibility code */
00530           local_glib_message_func (message);
00531           return;
00532         }
00533       ensure_stdout_valid ();
00534       if (log_domain)
00535         {
00536           write (fd, log_domain, strlen (log_domain));
00537           write (fd, "-", 1);
00538         }
00539       if (in_recursion)
00540         write (fd, "Message (recursed): ", 20);
00541       else
00542         write (fd, "Message: ", 9);
00543       write (fd, message, strlen(message));
00544       if (is_fatal)
00545         write (fd, "\naborting...\n", 13);
00546       else
00547         write (fd, "\n", 1);
00548       break;
00549     case G_LOG_LEVEL_INFO:
00550       ensure_stdout_valid ();
00551       if (log_domain)
00552         {
00553           write (fd, log_domain, strlen (log_domain));
00554           write (fd, "-", 1);
00555         }
00556       if (in_recursion)
00557         write (fd, "INFO (recursed): ", 17);
00558       else
00559         write (fd, "INFO: ", 6);
00560       write (fd, message, strlen(message));
00561       if (is_fatal)
00562         write (fd, "\naborting...\n", 13);
00563       else
00564         write (fd, "\n", 1);
00565       break;
00566     case G_LOG_LEVEL_DEBUG:
00567       ensure_stdout_valid ();
00568       if (log_domain)
00569         {
00570           write (fd, log_domain, strlen (log_domain));
00571           write (fd, "-", 1);
00572         }
00573       if (in_recursion)
00574         write (fd, "DEBUG (recursed): ", 18);
00575       else
00576         write (fd, "DEBUG: ", 7);
00577       write (fd, message, strlen(message));
00578       if (is_fatal)
00579         write (fd, "\naborting...\n", 13);
00580       else
00581         write (fd, "\n", 1);
00582       break;
00583     default:
00584       /* we are used for a log level that is not defined by GLib itself,
00585        * try to make the best out of it.
00586        */
00587       ensure_stdout_valid ();
00588       if (log_domain)
00589         {
00590           write (fd, log_domain, strlen (log_domain));
00591           if (in_recursion)
00592             write (fd, "-LOG (recursed:", 15);
00593           else
00594             write (fd, "-LOG (", 6);
00595         }
00596       else if (in_recursion)
00597         write (fd, "LOG (recursed:", 14);
00598       else
00599         write (fd, "LOG (", 5);
00600       if (log_level)
00601         {
00602           gchar string[] = "0x00): ";
00603           gchar *p = string + 2;
00604           guint i;
00605           
00606           i = g_bit_nth_msf (log_level, -1);
00607           *p = i >> 4;
00608           p++;
00609           *p = '0' + (i & 0xf);
00610           if (*p > '9')
00611             *p += 'A' - '9' - 1;
00612           
00613           write (fd, string, 7);
00614         }
00615       else
00616         write (fd, "): ", 3);
00617       write (fd, message, strlen(message));
00618       if (is_fatal)
00619         write (fd, "\naborting...\n", 13);
00620       else
00621         write (fd, "\n", 1);
00622       break;
00623     }
00624 }
00625 
00626 GPrintFunc
00627 g_set_print_handler (GPrintFunc func)
00628 {
00629   GPrintFunc old_print_func;
00630   
00631   g_mutex_lock (g_messages_lock);
00632   old_print_func = glib_print_func;
00633   glib_print_func = func;
00634   g_mutex_unlock (g_messages_lock);
00635   
00636   return old_print_func;
00637 }
00638 
00639 void
00640 g_print (const gchar *format,
00641          ...)
00642 {
00643   va_list args;
00644   gchar *string;
00645   GPrintFunc local_glib_print_func;
00646   
00647   g_return_if_fail (format != NULL);
00648   
00649   va_start (args, format);
00650   string = g_strdup_vprintf (format, args);
00651   va_end (args);
00652   
00653   g_mutex_lock (g_messages_lock);
00654   local_glib_print_func = glib_print_func;
00655   g_mutex_unlock (g_messages_lock);
00656 
00657   if (local_glib_print_func)
00658     local_glib_print_func (string);
00659   else
00660     {
00661       ensure_stdout_valid ();
00662       fputs (string, stdout);
00663       fflush (stdout);
00664     }
00665   g_free (string);
00666 }
00667 
00668 GPrintFunc
00669 g_set_printerr_handler (GPrintFunc func)
00670 {
00671   GPrintFunc old_printerr_func;
00672   
00673   g_mutex_lock (g_messages_lock);
00674   old_printerr_func = glib_printerr_func;
00675   glib_printerr_func = func;
00676   g_mutex_unlock (g_messages_lock);
00677   
00678   return old_printerr_func;
00679 }
00680 
00681 void
00682 g_printerr (const gchar *format,
00683             ...)
00684 {
00685   va_list args;
00686   gchar *string;
00687   GPrintFunc local_glib_printerr_func;
00688   
00689   g_return_if_fail (format != NULL);
00690   
00691   va_start (args, format);
00692   string = g_strdup_vprintf (format, args);
00693   va_end (args);
00694   
00695   g_mutex_lock (g_messages_lock);
00696   local_glib_printerr_func = glib_printerr_func;
00697   g_mutex_unlock (g_messages_lock);
00698 
00699   if (local_glib_printerr_func)
00700     local_glib_printerr_func (string);
00701   else
00702     {
00703       fputs (string, stderr);
00704       fflush (stderr);
00705     }
00706   g_free (string);
00707 }
00708 
00709 /* compatibility code */
00710 GErrorFunc
00711 g_set_error_handler (GErrorFunc func)
00712 {
00713   GErrorFunc old_error_func;
00714   
00715   g_mutex_lock (g_messages_lock);
00716   old_error_func = glib_error_func;
00717   glib_error_func = func;
00718   g_mutex_unlock (g_messages_lock);
00719  
00720   return old_error_func;
00721 }
00722 
00723 /* compatibility code */
00724 GWarningFunc
00725 g_set_warning_handler (GWarningFunc func)
00726 {
00727   GWarningFunc old_warning_func;
00728   
00729   g_mutex_lock (g_messages_lock);
00730   old_warning_func = glib_warning_func;
00731   glib_warning_func = func;
00732   g_mutex_unlock (g_messages_lock);
00733   
00734   return old_warning_func;
00735 }
00736 
00737 /* compatibility code */
00738 GPrintFunc
00739 g_set_message_handler (GPrintFunc func)
00740 {
00741   GPrintFunc old_message_func;
00742   
00743   g_mutex_lock (g_messages_lock);
00744   old_message_func = glib_message_func;
00745   glib_message_func = func;
00746   g_mutex_unlock (g_messages_lock);
00747   
00748   return old_message_func;
00749 }
00750 
00751 void
00752 g_messages_init (void)
00753 {
00754   g_messages_lock = g_mutex_new();
00755   g_log_depth = g_private_new(NULL);
00756 }

© sourcejam.com 2005-2008