OSDN Git Service

Support assignment of DEBUGLEVEL at configure time.
[mingw/mingw-get.git] / src / dmh.cpp
1 /*
2  * dmh.cpp
3  *
4  * $Id$
5  *
6  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7  * Copyright (C) 2009, 2010, 2011, MinGW Project
8  *
9  *
10  * Implementation of the diagnostic message handling subsystem.
11  *
12  *
13  * This is free software.  Permission is granted to copy, modify and
14  * redistribute this software, under the provisions of the GNU General
15  * Public License, Version 3, (or, at your option, any later version),
16  * as published by the Free Software Foundation; see the file COPYING
17  * for licensing details.
18  *
19  * Note, in particular, that this software is provided "as is", in the
20  * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
21  * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
22  * PARTICULAR PURPOSE.  Under no circumstances will the author, or the
23  * MinGW Project, accept liability for any damages, however caused,
24  * arising from the use of this software.
25  *
26  */
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30
31 #include "dmh.h"
32
33 class dmhTypeGeneric
34 {
35   /* Abstract base class, from which message handlers are derived.
36    */
37   public:
38     dmhTypeGeneric( const char* );
39     virtual uint16_t control( const uint16_t, const uint16_t ) = 0;
40     virtual int notify( const dmh_severity, const char*, va_list ) = 0;
41     virtual int printf( const char*, va_list ) = 0;
42
43   protected:
44     const char *progname;
45 };
46
47 class dmhTypeTTY : public dmhTypeGeneric
48 {
49   /* Diagnostic message handler for use in console applications.
50    */
51   public:
52     dmhTypeTTY( const char* );
53     virtual uint16_t control( const uint16_t, const uint16_t );
54     virtual int notify( const dmh_severity, const char*, va_list );
55     virtual int printf( const char*, va_list );
56
57   private:
58     inline int emit_and_flush( int );
59 };
60
61 class dmhTypeGUI : public dmhTypeGeneric
62 {
63   /* Diagnostic message handler for use in window applications.
64    */
65   public:
66     dmhTypeGUI( const char* );
67     virtual uint16_t control( const uint16_t, const uint16_t );
68     virtual int notify( const dmh_severity, const char*, va_list );
69     virtual int printf( const char*, va_list );
70 };
71
72 dmh_exception::dmh_exception() throw()
73 : message( "Unspecified error" )
74 {}
75
76 dmh_exception::dmh_exception::dmh_exception(const char * msg) throw()
77 : message( "Unspecified error" )
78 {
79   if( msg && *msg )
80     message = msg;
81 }
82
83 dmh_exception::~dmh_exception() throw()
84 {}
85
86 const char* dmh_exception::what() const throw()
87 {
88   return message;
89 }
90
91 /* Constructors serve to initialise the message handler,
92  * simply creating the class instance, and storing the specified
93  * program name within it.
94  */
95 dmhTypeGeneric::dmhTypeGeneric( const char* name ):progname( name ){}
96 dmhTypeTTY::dmhTypeTTY( const char* name ):dmhTypeGeneric( name ){}
97 dmhTypeGUI::dmhTypeGUI( const char* name ):dmhTypeGeneric( name ){}
98
99 /* This pointer stores the address of the message handler
100  * class instance, after initialisation.
101  */
102 static dmhTypeGeneric *dmh = NULL;
103
104 EXTERN_C void dmh_init( const dmh_class subsystem, const char *progname )
105 {
106   /* Public entry point for message handler initialisation...
107    *
108    * We only do it once, silently ignoring any attempt to
109    * establish a second handler.
110    */
111   if( dmh == NULL )
112   {
113     /* No message handler has yet been initialised;
114      * passing the specified program name, select...
115      */
116     if( subsystem == DMH_SUBSYSTEM_GUI )
117       /*
118        * ...a GUI class handler on demand...
119        */
120       dmh = new dmhTypeGUI( progname );
121
122     else
123       /* ...otherwise, a console class handler by default.
124        */
125       dmh = new dmhTypeTTY( progname );
126   }
127 }
128
129 static inline
130 int abort_if_fatal( const dmh_severity code, int status )
131 {
132   /* Helper function to abort an application, on notification
133    * of a DMH_FATAL exception.
134    */
135   if( code == DMH_FATAL )
136     throw dmh_exception( "Fatal error occured" );
137
138   /* If the exception wasn't DMH_FATAL, then fall through to
139    * return the specified status code.
140    */
141   return status;
142 }
143
144 uint16_t dmhTypeGUI::control( const uint16_t request, const uint16_t mask )
145 {
146   /* Select optional features of the GUI class message handler.
147    *
148    * FIXME: this is a stub; implementation to be provided.
149    */
150   return 0;
151 }
152
153 int dmhTypeGUI::notify( const dmh_severity code, const char *fmt, va_list argv )
154 {
155   /* Message dispatcher for GUI applications.
156    *
157    * FIXME: this is a stub; implementation to be provided.
158    */
159   return
160   fprintf( stderr, "%s: *** ERROR *** DMH_SUBSYSTEM_GUI not yet implemented\n", progname );
161 }
162
163 int dmhTypeGUI::printf( const char *fmt, va_list argv )
164 {
165   /* Display arbitrary text messages via the diagnostic message handler.
166    *
167    * FIXME: this is a stub; implementation to be provided.
168    */
169   return notify( DMH_ERROR, fmt, argv );
170 }
171
172 uint16_t dmhTypeTTY::control( const uint16_t request, const uint16_t mask )
173 {
174   /* Select optional features of the console class message handler.
175    * This message handler provides no optional features; we make this
176    * a "no-op".
177    */
178   return 0;
179 }
180
181 inline int dmhTypeTTY::emit_and_flush( int status )
182 {
183   /* Users of MSYS terminal emulators, in place of the standard
184    * MS-Windows console, may experience an I/O buffering issue on
185    * stderr (?!!) which may result in apparently erratic delivery
186    * of progress reporting diagnostics; this may lead to a false
187    * impression that mingw-get has stalled.  This inline wrapper
188    * ensures that any buffer which is improperly associated with
189    * stderr is flushed after each message is posted; this may
190    * mitigate the improper buffering issue.
191    */
192   fflush( stderr );
193   return status;
194 }
195
196 int dmhTypeTTY::notify( const dmh_severity code, const char *fmt, va_list argv )
197 {
198   /* Message dispatcher for console class applications.
199    */
200   static const char *severity[] =
201   {
202     /* Labels to identify message severity...
203      */
204     "INFO",             /* DMH_INFO */
205     "WARNING",          /* DMH_WARNING */
206     "ERROR",            /* DMH_ERROR */
207     "FATAL"             /* DMH_FATAL */
208   };
209
210   /* Dispatch the message to standard error, terminate application
211    * if DMH_FATAL, else continue, returning the message length.
212    */
213   return abort_if_fatal( code,
214       emit_and_flush(
215         fprintf( stderr, "%s: *** %s *** ", progname, severity[code] )
216         + vfprintf( stderr, fmt, argv )
217         )
218       );
219 }
220
221 int dmhTypeTTY::printf( const char *fmt, va_list argv )
222 {
223   /* Display arbitrary text messages via the diagnostic message handler;
224    * for the TTY subsystem, this is equivalent to printf() on stderr.
225    */
226   return emit_and_flush( vfprintf( stderr, fmt, argv ) );
227 }
228
229 EXTERN_C uint16_t dmh_control( const uint16_t request, const uint16_t mask )
230 {
231   return dmh->control( request, mask );
232 }
233
234 EXTERN_C int dmh_notify( const dmh_severity code, const char *fmt, ... )
235 {
236   /* Public entry point for diagnostic message dispatcher.
237    */
238   if( dmh == NULL )
239   {
240     /* The message handler has been called before initialising it;
241      * this is an internal program error -- treat it as fatal!
242      */
243     dmh_init( DMH_SUBSYSTEM_TTY, "dmh" );
244     dmh_notify( DMH_FATAL, "message handler was not initialised\n" );
245   }
246
247   /* Normal operation; pass the message on to the active handler.
248    */
249   va_list argv;
250   va_start( argv, fmt );
251   int retcode = dmh->notify( code, fmt, argv );
252   va_end( argv );
253   return retcode;
254 }
255
256 EXTERN_C int dmh_printf( const char *fmt, ... )
257 {
258   /* Simulate standard printf() function calls, redirecting the display
259    * of formatted output through the diagnostic message handler.
260    */
261   va_list argv;
262   va_start( argv, fmt );
263   int retcode = dmh->printf( fmt, argv );
264   va_end( argv );
265   return retcode;
266 }
267
268 /* $RCSfile$: end of file */