1 // Log.cs - Wrapper for message logging functions
2 //
3 // Authors:
4 //	Gonzalo Paniagua Javier (gonzalo@ximian.com)
5 //
6 //
7 // Copyright (c) 2002 Gonzalo Paniagua
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of version 2 of the Lesser GNU General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this program; if not, write to the
20 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 // Boston, MA 02111-1307, USA.
22 
23 //
24 
25 namespace GLib {
26 
27 	using System;
28 	using System.Runtime.InteropServices;
29 
LogFunc(string log_domain, LogLevelFlags log_level, string message)30 	public delegate void LogFunc (string log_domain, LogLevelFlags log_level, string message);
31 
PrintFunc(string message)32 	public delegate void PrintFunc (string message);
33 
34 	[Flags]
35 	public enum LogLevelFlags : int
36 	{
37 		/* log flags */
38 		FlagRecursion          = 1 << 0,
39 		FlagFatal              = 1 << 1,
40 
41 		/* GLib log levels */
42 		Error                  = 1 << 2,       /* always fatal */
43 		Critical               = 1 << 3,
44 		Warning                = 1 << 4,
45 		Message                = 1 << 5,
46 		Info                   = 1 << 6,
47 		Debug                  = 1 << 7,
48 
49 		/* Convenience values */
50 		AllButFatal            = 253,
51 		AllButRecursion        = 254,
52 		All                    = 255,
53 
54 		FlagMask               = 3,
55 		LevelMask              = unchecked ((int) 0xFFFFFFFC)
56 	}
57 
58 	public class Log {
59 
60 		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
LogFuncNative(IntPtr log_domain, LogLevelFlags flags, IntPtr message, IntPtr user_data)61 		delegate void LogFuncNative (IntPtr log_domain, LogLevelFlags flags, IntPtr message, IntPtr user_data);
62 
63 		static LogFuncNative native_handler;
64 
NativeCallback(IntPtr log_domain_native, LogLevelFlags flags, IntPtr message_native, IntPtr user_data)65 		static void NativeCallback (IntPtr log_domain_native, LogLevelFlags flags, IntPtr message_native, IntPtr user_data)
66 		{
67 			if (user_data == IntPtr.Zero)
68 				return;
69 			string log_domain = Marshaller.Utf8PtrToString (log_domain_native);
70 			string message = Marshaller.Utf8PtrToString (message_native);
71 			GCHandle gch = (GCHandle) user_data;
72 			LogFunc func = gch.Target as LogFunc;
73 			if (func != null)
74 				func (log_domain, flags, message);
75 		}
76 
77 		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
PrintFuncNative(IntPtr message)78 		delegate void PrintFuncNative (IntPtr message);
79 
80 		class PrintHelper {
81 
82 			PrintFuncNative native;
83 			PrintFunc managed;
84 
PrintHelper(PrintFuncNative native)85 			public PrintHelper (PrintFuncNative native)
86 			{
87 				this.native = native;
88 			}
89 
PrintHelper(PrintFunc managed)90 			public PrintHelper (PrintFunc managed)
91 			{
92 				this.managed = managed;
93 				GCHandle.Alloc (this);
94 			}
95 
Callback(IntPtr nmessage)96 			void Callback (IntPtr nmessage)
97 			{
98 				string message = Marshaller.Utf8PtrToString (nmessage);
99 				managed (message);
100 			}
101 
Invoke(string message)102 			void Invoke (string message)
103 			{
104 				IntPtr nmessage = Marshaller.StringToPtrGStrdup (message);
105 				native (nmessage);
106 				Marshaller.Free (nmessage);
107 			}
108 
109 			public PrintFuncNative Handler {
110 				get { return new PrintFuncNative (Callback); }
111 			}
112 
113 			public PrintFunc Invoker {
114 				get { return new PrintFunc (Invoke); }
115 			}
116 		}
117 
118 		static System.Collections.Generic.Dictionary<uint, GCHandle> handlers;
119 
EnsureHash()120 		static void EnsureHash ()
121 		{
122 			if (handlers == null)
123 				handlers = new System.Collections.Generic.Dictionary<uint, GCHandle> ();
124 		}
125 
126 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_logv(IntPtr log_domain, LogLevelFlags flags, IntPtr message)127 		static extern void g_logv (IntPtr log_domain, LogLevelFlags flags, IntPtr message);
128 
WriteLog(string logDomain, LogLevelFlags flags, string format, params object [] args)129 		public void WriteLog (string logDomain, LogLevelFlags flags, string format, params object [] args)
130 		{
131 			IntPtr ndom = Marshaller.StringToPtrGStrdup (logDomain);
132 			IntPtr nmessage = Marshaller.StringToPtrGStrdup (String.Format (format, args));
133 			g_logv (ndom, flags, nmessage);
134 			Marshaller.Free (ndom);
135 			Marshaller.Free (nmessage);
136 		}
137 
138 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_log_set_handler(IntPtr log_domain, LogLevelFlags flags, LogFuncNative log_func, IntPtr user_data)139 		static extern uint g_log_set_handler (IntPtr log_domain, LogLevelFlags flags, LogFuncNative log_func, IntPtr user_data);
140 
SetLogHandler(string logDomain, LogLevelFlags flags, LogFunc logFunc)141 		public static uint SetLogHandler (string logDomain, LogLevelFlags flags, LogFunc logFunc)
142 		{
143 			if (native_handler == null)
144 				native_handler = new LogFuncNative (NativeCallback);
145 
146 			IntPtr ndom = Marshaller.StringToPtrGStrdup (logDomain);
147 			GCHandle gch = GCHandle.Alloc (logFunc);
148 			uint result = g_log_set_handler (ndom, flags, native_handler, (IntPtr) gch);
149 			Marshaller.Free (ndom);
150 			EnsureHash ();
151 			handlers [result] = gch;
152 			return result;
153 		}
154 
155 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_log_remove_handler(IntPtr log_domain, uint handler_id)156 		static extern uint g_log_remove_handler (IntPtr log_domain, uint handler_id);
157 
RemoveLogHandler(string logDomain, uint handlerID)158 		public static void RemoveLogHandler (string logDomain, uint handlerID)
159 		{
160 			if (handlers != null && handlers.ContainsKey (handlerID)) {
161 				handlers [handlerID].Free ();
162 				handlers.Remove (handlerID);
163 			}
164 
165 			IntPtr ndom = Marshaller.StringToPtrGStrdup (logDomain);
166 			g_log_remove_handler (ndom, handlerID);
167 			Marshaller.Free (ndom);
168 		}
169 
170 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_set_print_handler(PrintFuncNative handler)171 		static extern PrintFuncNative g_set_print_handler (PrintFuncNative handler);
172 
SetPrintHandler(PrintFunc handler)173 		public static PrintFunc SetPrintHandler (PrintFunc handler)
174 		{
175 			PrintHelper helper = new PrintHelper (handler);
176 			PrintFuncNative prev = g_set_print_handler (helper.Handler);
177 			helper = new PrintHelper (prev);
178 			return helper.Invoker;
179 		}
180 
181 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_set_printerr_handler(PrintFuncNative handler)182 		static extern PrintFuncNative g_set_printerr_handler (PrintFuncNative handler);
183 
SetPrintErrorHandler(PrintFunc handler)184 		public static PrintFunc SetPrintErrorHandler (PrintFunc handler)
185 		{
186 			PrintHelper helper = new PrintHelper (handler);
187 			PrintFuncNative prev = g_set_printerr_handler (helper.Handler);
188 			helper = new PrintHelper (prev);
189 			return helper.Invoker;
190 		}
191 
192 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_log_default_handler(IntPtr log_domain, LogLevelFlags log_level, IntPtr message, IntPtr unused_data)193 		static extern void g_log_default_handler (IntPtr log_domain, LogLevelFlags log_level, IntPtr message, IntPtr unused_data);
194 
DefaultHandler(string logDomain, LogLevelFlags logLevel, string message)195 		public static void DefaultHandler (string logDomain, LogLevelFlags logLevel, string message)
196 
197 		{
198 			IntPtr ndom = Marshaller.StringToPtrGStrdup (logDomain);
199 			IntPtr nmess = Marshaller.StringToPtrGStrdup (message);
200 			g_log_default_handler (ndom, logLevel, nmess, IntPtr.Zero);
201 			Marshaller.Free (ndom);
202 			Marshaller.Free (nmess);
203 		}
204 
205 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_log_set_always_fatal(LogLevelFlags fatal_mask)206 		extern static LogLevelFlags g_log_set_always_fatal (LogLevelFlags fatal_mask);
207 
SetAlwaysFatal(LogLevelFlags fatalMask)208 		public static LogLevelFlags SetAlwaysFatal (LogLevelFlags fatalMask)
209 		{
210 			return g_log_set_always_fatal (fatalMask);
211 		}
212 
213 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_log_set_fatal_mask(IntPtr log_domain, LogLevelFlags fatal_mask)214 		extern static LogLevelFlags g_log_set_fatal_mask (IntPtr log_domain, LogLevelFlags fatal_mask);
215 
SetAlwaysFatal(string logDomain, LogLevelFlags fatalMask)216 		public static LogLevelFlags SetAlwaysFatal (string logDomain, LogLevelFlags fatalMask)
217 		{
218 			IntPtr ndom = Marshaller.StringToPtrGStrdup (logDomain);
219 			LogLevelFlags result = g_log_set_fatal_mask (ndom, fatalMask);
220 			Marshaller.Free (ndom);
221 			return result;
222 		}
223 
224 		class Invoker {
225 
226 			LogFuncNative native;
227 
Invoker(LogFuncNative native)228 			public Invoker (LogFuncNative native)
229 			{
230 				this.native = native;
231 			}
232 
Invoke(string log_domain, LogLevelFlags flags, string message)233 			void Invoke (string log_domain, LogLevelFlags flags, string message)
234 			{
235 				IntPtr ndom = Marshaller.StringToPtrGStrdup (log_domain);
236 				IntPtr nmess = Marshaller.StringToPtrGStrdup (message);
237 				native (ndom, flags, nmess, IntPtr.Zero);
238 				Marshaller.Free (ndom);
239 				Marshaller.Free (nmess);
240 			}
241 
242 			public LogFunc Handler {
243 				get { return new LogFunc (Invoke); }
244 			}
245 		}
246 
247 		[DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_log_set_default_handler(LogFuncNative log_func, IntPtr user_data)248 		extern static LogFuncNative g_log_set_default_handler (LogFuncNative log_func, IntPtr user_data);
249 
SetDefaultHandler(LogFunc log_func)250 		public static LogFunc SetDefaultHandler (LogFunc log_func)
251 		{
252 			if (native_handler == null)
253 				native_handler = new LogFuncNative (NativeCallback);
254 
255 			LogFuncNative prev = g_log_set_default_handler (native_handler, (IntPtr) GCHandle.Alloc (log_func));
256 			if (prev == null)
257 				return null;
258 			Invoker invoker = new Invoker (prev);
259 			return invoker.Handler;
260 		}
261 
262 		/*
263 		 * Some common logging methods.
264 		 *
265 		 * Sample usage:
266 		 *
267 		 *	// Print the messages for the NULL domain
268 		 *	LogFunc logFunc = new LogFunc (Log.PrintLogFunction);
269 		 *	Log.SetLogHandler (null, LogLevelFlags.All, logFunc);
270 		 *
271 		 *	// Print messages and stack trace for Gtk critical messages
272 		 *	logFunc = new LogFunc (Log.PrintTraceLogFunction);
273 		 *	Log.SetLogHandler ("Gtk", LogLevelFlags.Critical, logFunc);
274 		 *
275 		 */
276 
PrintLogFunction(string domain, LogLevelFlags level, string message)277 		public static void PrintLogFunction (string domain, LogLevelFlags level, string message)
278 		{
279 			Console.WriteLine ("Domain: '{0}' Level: {1}", domain, level);
280 			Console.WriteLine ("Message: {0}", message);
281 		}
282 
PrintTraceLogFunction(string domain, LogLevelFlags level, string message)283 		public static void PrintTraceLogFunction (string domain, LogLevelFlags level, string message)
284 		{
285 			PrintLogFunction (domain, level, message);
286 			Console.WriteLine ("Trace follows:\n{0}", new System.Diagnostics.StackTrace ());
287 		}
288 	}
289 }
290 
291