1 /*
2  * Copyright 2001 Red Hat Inc., Durham, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 /*
29  * Authors:
30  *   Rickard E. (Rik) Faith <faith@redhat.com>
31  *
32  */
33 
34 /** \file
35  * This file encapsulated all of the logging functions that are used by
36  * DMX for informational, warning, and error messages. */
37 
38 #ifdef HAVE_DMX_CONFIG_H
39 #include <dmx-config.h>
40 #endif
41 
42 #include "dmx.h"
43 #include "dmxlog.h"
44 #include "dmxinput.h"
45 #include <X11/extensions/XI.h>
46 #include <X11/extensions/XIproto.h>
47 
48 static dmxLogLevel dmxCurrentLogLevel = dmxDebug;
49 
50 /** Set the default level for logging to #dmxLogLevel.  Returns the
51  * previous log level. */
52 dmxLogLevel
dmxSetLogLevel(dmxLogLevel newLevel)53 dmxSetLogLevel(dmxLogLevel newLevel)
54 {
55     dmxLogLevel oldLevel = dmxCurrentLogLevel;
56 
57     if (newLevel > dmxFatal)
58         newLevel = dmxFatal;
59     dmxCurrentLogLevel = newLevel;
60     return oldLevel;
61 }
62 
63 /** Returns the log level set by #dmxLogLevel. */
64 dmxLogLevel
dmxGetLogLevel(void)65 dmxGetLogLevel(void)
66 {
67     return dmxCurrentLogLevel;
68 }
69 
70 #ifdef DMX_LOG_STANDALONE
71 /* When using this file as part of a stand-alone (i.e., non-X-Server
72  * program, then the ultimate output routines have to be defined.  */
73 
74 /** Provide an ErrorF function when used stand-alone. */
75 void
ErrorF(const char * format,...)76 ErrorF(const char *format, ...)
77 {
78     va_list args;
79 
80     va_start(args, format);
81     vfprintf(stderr, format, args);     /* RATS: We assume the format string
82                                          * is trusted, since it is always
83                                          * from a log message in our code. */
84     va_end(args);
85 }
86 
87 /** Provide an VFatalError function when used stand-alone. */
88 static void
89 VFatalError(const char *format, va_list args) _X_ATTRIBUTE_PRINTF(1, 0) _X_NORETURN;
90 static void
VFatalError(const char * format,va_list args)91 VFatalError(const char *format, va_list args)
92 {
93     vfprintf(stderr, format, args);     /* RATS: We assume the format string
94                                          * is trusted, since it is always
95                                          * from a log message in our code. */
96     exit(1);
97 }
98 
99 /** Provide an VErrorF function when used stand-alone. */
100 void
VErrorF(const char * format,va_list args)101 VErrorF(const char *format, va_list args)
102 {
103     vfprintf(stderr, format, args);     /* RATS: We assume the format string
104                                          * is trusted, since it is always
105                                          * from a log message in our code. */
106 }
107 #else
108 /** This function was removed between XFree86 4.3.0 and XFree86 4.4.0. */
109 extern void AbortServer(void) _X_NORETURN;
110 static void
111 VFatalError(const char *format, va_list args) _X_ATTRIBUTE_PRINTF(1, 0) _X_NORETURN;
112 static void
VFatalError(const char * format,va_list args)113 VFatalError(const char *format, va_list args)
114 {
115     VErrorF(format, args);
116     ErrorF("\n");
117     AbortServer();
118  /*NOTREACHED*/}
119 #endif
120 
121 /* Prints a consistent header for each line. */
122 static void
dmxHeader(dmxLogLevel logLevel,DMXInputInfo * dmxInput,DMXScreenInfo * dmxScreen)123 dmxHeader(dmxLogLevel logLevel, DMXInputInfo * dmxInput,
124           DMXScreenInfo * dmxScreen)
125 {
126     const char *type = "??";
127 
128     switch (logLevel) {
129     case dmxDebug:
130         type = "..";
131         break;
132     case dmxInfo:
133         type = "II";
134         break;
135     case dmxWarning:
136         type = "**";
137         break;
138     case dmxError:
139         type = "!!";
140         break;
141     case dmxFatal:
142         type = "Fatal Error";
143         break;
144     }
145 
146     if (dmxInput && dmxScreen) {
147         ErrorF("(%s) dmx[i%d/%s;o%d/%s]: ", type,
148                dmxInput->inputIdx, dmxInput->name,
149                dmxScreen->index, dmxScreen->name);
150     }
151     else if (dmxScreen) {
152         ErrorF("(%s) dmx[o%d/%s]: ", type, dmxScreen->index, dmxScreen->name);
153     }
154     else if (dmxInput) {
155         const char *pt = strchr(dmxInput->name, ',');
156         int len = (pt ? (size_t) (pt - dmxInput->name)
157                    : strlen(dmxInput->name));
158 
159         ErrorF("(%s) dmx[i%d/%*.*s]: ", type,
160                dmxInput->inputIdx, len, len, dmxInput->name);
161     }
162     else {
163         ErrorF("(%s) dmx: ", type);
164     }
165 }
166 
167 /* Prints the error message with the appropriate low-level X output
168  * routine. */
169 static void
170 dmxMessage(dmxLogLevel logLevel, const char *format, va_list args) _X_ATTRIBUTE_PRINTF(2, 0);
171 static void
dmxMessage(dmxLogLevel logLevel,const char * format,va_list args)172 dmxMessage(dmxLogLevel logLevel, const char *format, va_list args)
173 {
174     if (logLevel == dmxFatal || logLevel >= dmxCurrentLogLevel) {
175         if (logLevel == dmxFatal)
176             VFatalError(format, args);
177         else
178             VErrorF(format, args);
179     }
180 }
181 
182 /** Log the specified message at the specified \a logLevel.  \a format
183  * can be a printf-like format expression. */
184 void
dmxLog(dmxLogLevel logLevel,const char * format,...)185 dmxLog(dmxLogLevel logLevel, const char *format, ...)
186 {
187     va_list args;
188 
189     dmxHeader(logLevel, NULL, NULL);
190     va_start(args, format);
191     dmxMessage(logLevel, format, args);
192     va_end(args);
193 }
194 
195 /** Continue a log message without printing the message prefix. */
196 void
dmxLogCont(dmxLogLevel logLevel,const char * format,...)197 dmxLogCont(dmxLogLevel logLevel, const char *format, ...)
198 {
199     va_list args;
200 
201     va_start(args, format);
202     dmxMessage(logLevel, format, args);
203     va_end(args);
204 }
205 
206 #ifndef DMX_LOG_STANDALONE
207 /** Log an informational message (at level #dmxInfo) related to ouput.
208  * The message prefix will contain backend information from \a
209  * dmxScreen. */
210 void
dmxLogOutput(DMXScreenInfo * dmxScreen,const char * format,...)211 dmxLogOutput(DMXScreenInfo * dmxScreen, const char *format, ...)
212 {
213     va_list args;
214 
215     dmxHeader(dmxInfo, NULL, dmxScreen);
216     va_start(args, format);
217     dmxMessage(dmxInfo, format, args);
218     va_end(args);
219 }
220 
221 /** Continue a message related to output without printing the message
222  * prefix. */
223 void
dmxLogOutputCont(DMXScreenInfo * dmxScreen,const char * format,...)224 dmxLogOutputCont(DMXScreenInfo * dmxScreen, const char *format, ...)
225 {
226     va_list args;
227 
228     va_start(args, format);
229     dmxMessage(dmxInfo, format, args);
230     va_end(args);
231 }
232 
233 /** Log a warning message (at level #dmxWarning) related to output.
234  * The message prefix will contain backend information from \a
235  * dmxScreen. */
236 void
dmxLogOutputWarning(DMXScreenInfo * dmxScreen,const char * format,...)237 dmxLogOutputWarning(DMXScreenInfo * dmxScreen, const char *format, ...)
238 {
239     va_list args;
240 
241     dmxHeader(dmxWarning, NULL, dmxScreen);
242     va_start(args, format);
243     dmxMessage(dmxWarning, format, args);
244     va_end(args);
245 }
246 
247 /** Log an informational message (at level #dmxInfo) related to input.
248  * The message prefix will contain information from \a dmxInput. */
249 void
dmxLogInput(DMXInputInfo * dmxInput,const char * format,...)250 dmxLogInput(DMXInputInfo * dmxInput, const char *format, ...)
251 {
252     va_list args;
253 
254     dmxHeader(dmxInfo, dmxInput, NULL);
255     va_start(args, format);
256     dmxMessage(dmxInfo, format, args);
257     va_end(args);
258 }
259 
260 /** Continue a message related to input without printing the message
261  * prefix. */
262 void
dmxLogInputCont(DMXInputInfo * dmxInput,const char * format,...)263 dmxLogInputCont(DMXInputInfo * dmxInput, const char *format, ...)
264 {
265     va_list args;
266 
267     va_start(args, format);
268     dmxMessage(dmxInfo, format, args);
269     va_end(args);
270 }
271 
272 /** Print \a argc messages, each describing an element in \a argv.  This
273  * is maingly for debugging purposes. */
274 void
dmxLogArgs(dmxLogLevel logLevel,int argc,char ** argv)275 dmxLogArgs(dmxLogLevel logLevel, int argc, char **argv)
276 {
277     int i;
278 
279     for (i = 0; i < argc; i++)
280         dmxLog(logLevel, "   Arg[%d] = \"%s\"\n", i, argv[i]);
281 }
282 
283 /** Print messages at level #dmxInfo describing the visuals in \a vi. */
284 void
dmxLogVisual(DMXScreenInfo * dmxScreen,XVisualInfo * vi,int defaultVisual)285 dmxLogVisual(DMXScreenInfo * dmxScreen, XVisualInfo * vi, int defaultVisual)
286 {
287     const char *class = "Unknown";
288 
289     switch (vi->class) {
290     case StaticGray:
291         class = "StaticGray ";
292         break;
293     case GrayScale:
294         class = "GrayScale  ";
295         break;
296     case StaticColor:
297         class = "StaticColor";
298         break;
299     case PseudoColor:
300         class = "PseudoColor";
301         break;
302     case TrueColor:
303         class = "TrueColor  ";
304         break;
305     case DirectColor:
306         class = "DirectColor";
307         break;
308     }
309 #define VisualLogFormat "0x%02lx %s %2db %db/rgb %3d 0x%04lx 0x%04lx 0x%04lx%s\n"
310 
311     if (dmxScreen) {
312         dmxLogOutput(dmxScreen,
313                      VisualLogFormat,
314                      vi->visualid, class, vi->depth, vi->bits_per_rgb,
315                      vi->colormap_size,
316                      vi->red_mask, vi->green_mask, vi->blue_mask,
317                      defaultVisual ? " *" : "");
318     }
319     else {
320         dmxLog(dmxInfo,
321                "  " VisualLogFormat,
322                vi->visualid, class, vi->depth, vi->bits_per_rgb,
323                vi->colormap_size,
324                vi->red_mask, vi->green_mask, vi->blue_mask,
325                defaultVisual ? " *" : "");
326     }
327 }
328 
329 /** Translate a (normalized) XInput event \a type into a human-readable
330  * string. */
331 const char *
dmxXInputEventName(int type)332 dmxXInputEventName(int type)
333 {
334     switch (type) {
335     case XI_DeviceValuator:
336         return "XI_DeviceValuator";
337     case XI_DeviceKeyPress:
338         return "XI_DeviceKeyPress";
339     case XI_DeviceKeyRelease:
340         return "XI_DeviceKeyRelease";
341     case XI_DeviceButtonPress:
342         return "XI_DeviceButtonPress";
343     case XI_DeviceButtonRelease:
344         return "XI_DeviceButtonRelease";
345     case XI_DeviceMotionNotify:
346         return "XI_DeviceMotionNotify";
347     case XI_DeviceFocusIn:
348         return "XI_DeviceFocusIn";
349     case XI_DeviceFocusOut:
350         return "XI_DeviceFocusOut";
351     case XI_ProximityIn:
352         return "XI_ProximityIn";
353     case XI_ProximityOut:
354         return "XI_ProximityOut";
355     case XI_DeviceStateNotify:
356         return "XI_DeviceStateNotify";
357     case XI_DeviceMappingNotify:
358         return "XI_DeviceMappingNotify";
359     case XI_ChangeDeviceNotify:
360         return "XI_ChangeDeviceNotify";
361     case XI_DeviceKeystateNotify:
362         return "XI_DeviceKeystateNotify";
363     case XI_DeviceButtonstateNotify:
364         return "XI_DeviceButtonstateNotify";
365     default:
366         return "unknown";
367     }
368 }
369 
370 #endif
371 
372 /** Translate an event \a type into a human-readable string. */
373 const char *
dmxEventName(int type)374 dmxEventName(int type)
375 {
376     switch (type) {
377     case KeyPress:
378         return "KeyPress";
379     case KeyRelease:
380         return "KeyRelease";
381     case ButtonPress:
382         return "ButtonPress";
383     case ButtonRelease:
384         return "ButtonRelease";
385     case MotionNotify:
386         return "MotionNotify";
387     case EnterNotify:
388         return "EnterNotify";
389     case LeaveNotify:
390         return "LeaveNotify";
391     case FocusIn:
392         return "FocusIn";
393     case FocusOut:
394         return "FocusOut";
395     case KeymapNotify:
396         return "KeymapNotify";
397     case Expose:
398         return "Expose";
399     case GraphicsExpose:
400         return "GraphicsExpose";
401     case NoExpose:
402         return "NoExpose";
403     case VisibilityNotify:
404         return "VisibilityNotify";
405     case CreateNotify:
406         return "CreateNotify";
407     case DestroyNotify:
408         return "DestroyNotify";
409     case UnmapNotify:
410         return "UnmapNotify";
411     case MapNotify:
412         return "MapNotify";
413     case MapRequest:
414         return "MapRequest";
415     case ReparentNotify:
416         return "ReparentNotify";
417     case ConfigureNotify:
418         return "ConfigureNotify";
419     case ConfigureRequest:
420         return "ConfigureRequest";
421     case GravityNotify:
422         return "GravityNotify";
423     case ResizeRequest:
424         return "ResizeRequest";
425     case CirculateNotify:
426         return "CirculateNotify";
427     case CirculateRequest:
428         return "CirculateRequest";
429     case PropertyNotify:
430         return "PropertyNotify";
431     case SelectionClear:
432         return "SelectionClear";
433     case SelectionRequest:
434         return "SelectionRequest";
435     case SelectionNotify:
436         return "SelectionNotify";
437     case ColormapNotify:
438         return "ColormapNotify";
439     case ClientMessage:
440         return "ClientMessage";
441     case MappingNotify:
442         return "MappingNotify";
443     default:
444         return "<unknown>";
445     }
446 }
447