OSDN Git Service

Fix "mingw-get deletes itself" bug in last rites handling.
[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, 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 *progname );
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
58 class dmhTypeGUI : public dmhTypeGeneric
59 {
60   /* Diagnostic message handler for use in window applications.
61    */
62   public:
63     dmhTypeGUI( const char *progname );
64     virtual uint16_t control( const uint16_t, const uint16_t );
65     virtual int notify( const dmh_severity, const char*, va_list );
66     virtual int printf( const char*, va_list );
67 };
68
69 dmh_exception::dmh_exception() throw()
70   : message("Unspecified error")
71 {}
72
73 dmh_exception::dmh_exception::dmh_exception(const char * msg) throw()
74   : message("Unspecified error")
75 {
76   if (msg && *msg)
77     message = msg;
78 }
79
80 dmh_exception::~dmh_exception() throw()
81 {}
82
83 const char * dmh_exception::what() const throw()
84 {
85   return message;
86 }
87
88 /* Constructors serve to initialise the message handler,
89  * simply creating the class instance, and storing the specified
90  * program name within it.
91  */
92 dmhTypeGeneric::dmhTypeGeneric( const char* name ):progname( name ){}
93 dmhTypeTTY::dmhTypeTTY( const char* name ):dmhTypeGeneric( name ){}
94 dmhTypeGUI::dmhTypeGUI( const char* name ):dmhTypeGeneric( name ){}
95
96 /* This pointer stores the address of the message handler
97  * class instance, after initialisation.
98  */
99 static dmhTypeGeneric *dmh = NULL;
100
101 EXTERN_C void dmh_init( const dmh_class subsystem, const char *progname )
102 {
103   /* Public entry point for message handler initialisation...
104    *
105    * We only do it once, silently ignoring any attempt to
106    * establish a second handler.
107    */
108   if( dmh == NULL )
109   {
110     /* No message handler has yet been initialised;
111      * passing the specified program name, select...
112      */
113     if( subsystem == DMH_SUBSYSTEM_GUI )
114       /*
115        * ...a GUI class handler on demand...
116        */
117       dmh = new dmhTypeGUI( progname );
118
119     else
120       /* ...otherwise, a console class handler by default.
121        */
122       dmh = new dmhTypeTTY( progname );
123   }
124 }
125
126 static inline
127 int abort_if_fatal( const dmh_severity code, int status )
128 {
129   /* Helper function to abort an application, on notification
130    * of a DMH_FATAL exception.
131    */
132   if( code == DMH_FATAL )
133     throw dmh_exception("Fatal error occured");
134
135   /* If the exception wasn't DMH_FATAL, then fall through to
136    * return the specified status code.
137    */
138   return status;
139 }
140
141 uint16_t dmhTypeGUI::control( const uint16_t request, const uint16_t mask )
142 {
143   /* Select optional features of the GUI class message handler.
144    *
145    * FIXME: this is a stub; implementation to be provided.
146    */
147   return 0;
148 }
149
150 int dmhTypeGUI::notify( const dmh_severity code, const char *fmt, va_list argv )
151 {
152   /* Message dispatcher for GUI applications.
153    *
154    * FIXME: this is a stub; implementation to be provided.
155    */
156   return
157   fprintf( stderr, "%s: *** ERROR *** DMH_SUBSYSTEM_GUI not yet implemented\n", progname );
158 }
159
160 int dmhTypeGUI::printf( const char *fmt, va_list argv )
161 {
162   /* Display arbitrary text messages via the diagnostic message handler.
163    *
164    * FIXME: this is a stub; implementation to be provided.
165    */
166   return notify( DMH_ERROR, fmt, argv );
167 }
168
169 uint16_t dmhTypeTTY::control( const uint16_t request, const uint16_t mask )
170 {
171   /* Select optional features of the console class message handler.
172    * This message handler provides no optional features; we make this
173    * a "no-op".
174    */
175   return 0;
176 }
177
178 int dmhTypeTTY::notify( const dmh_severity code, const char *fmt, va_list argv )
179 {
180   /* Message dispatcher for console class applications.
181    */
182   static const char *severity[] =
183   {
184     /* Labels to identify message severity...
185      */
186     "INFO",             /* DMH_INFO */
187     "WARNING",          /* DMH_WARNING */
188     "ERROR",            /* DMH_ERROR */
189     "FATAL"             /* DMH_FATAL */
190   };
191
192   /* Dispatch the message to standard error, terminate application
193    * if DMH_FATAL, else continue, returning the message length.
194    */
195   int retcode = fprintf( stderr, "%s: *** %s *** ", progname, severity[code] );
196   return abort_if_fatal( code, retcode + vfprintf( stderr, fmt, argv ) );
197 }
198
199 int dmhTypeTTY::printf( const char *fmt, va_list argv )
200 {
201   /* Display arbitrary text messages via the diagnostic message handler;
202    * for the TTY subsystem, this is equivalent to printf() on stderr.
203    */
204   return vfprintf( stderr, fmt, argv );
205 }
206
207 EXTERN_C uint16_t dmh_control( const uint16_t request, const uint16_t mask )
208 {
209   return dmh->control( request, mask );
210 }
211
212 EXTERN_C int dmh_notify( const dmh_severity code, const char *fmt, ... )
213 {
214   /* Public entry point for diagnostic message dispatcher.
215    */
216   if( dmh == NULL )
217   {
218     /* The message handler has been called before initialising it;
219      * this is an internal program error -- treat it as fatal!
220      */
221     dmh_init( DMH_SUBSYSTEM_TTY, "dmh" );
222     dmh_notify( DMH_FATAL, "message handler was not initialised\n" );
223   }
224
225   /* Normal operation; pass the message on to the active handler.
226    */
227   va_list argv;
228   va_start( argv, fmt );
229   int retcode = dmh->notify( code, fmt, argv );
230   va_end( argv );
231   return retcode;
232 }
233
234 EXTERN_C int dmh_printf( const char *fmt, ... )
235 {
236   /* Simulate standard printf() function calls, redirecting the display
237    * of formatted output through the diagnostic message handler.
238    */
239   va_list argv;
240   va_start( argv, fmt );
241   int retcode = dmh->printf( fmt, argv );
242   va_end( argv );
243   return retcode;
244 }
245
246 /* $RCSfile$: end of file */