6 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7 * Copyright (C) 2009, 2010, 2011, 2012, MinGW.org Project
10 * Implementation of the core components of, and the CLI specific
11 * API for, the diagnostic message handling subsystem.
14 * This is free software. Permission is granted to copy, modify and
15 * redistribute this software, under the provisions of the GNU General
16 * Public License, Version 3, (or, at your option, any later version),
17 * as published by the Free Software Foundation; see the file COPYING
18 * for licensing details.
20 * Note, in particular, that this software is provided "as is", in the
21 * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
22 * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
23 * PARTICULAR PURPOSE. Under no circumstances will the author, or the
24 * MinGW Project, accept liability for any damages, however caused,
25 * arising from the use of this software.
34 #define WIN32_LEAN_AND_MEAN
37 /* Implementation of the dmh_exception class.
39 static const char *unspecified_error = "Unspecified error";
41 dmh_exception::dmh_exception() throw():
42 message( unspecified_error ){}
44 dmh_exception::dmh_exception( const char *msg ) throw():
45 message( unspecified_error )
51 dmh_exception::~dmh_exception() throw(){}
53 const char* dmh_exception::what() const throw()
58 class dmhTypeTTY: public dmhTypeGeneric
60 /* Diagnostic message handler for use in console applications.
63 dmhTypeTTY( const char* );
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 );
69 inline int emit_and_flush( int );
72 /* Constructors serve to initialise the message handler,
73 * simply creating the class instance, and storing the specified
74 * program name within it.
76 dmhTypeGeneric::dmhTypeGeneric( const char* name ):progname( name ){}
77 dmhTypeTTY::dmhTypeTTY( const char* name ):dmhTypeGeneric( name ){}
79 /* This pointer stores the address of the message handler
80 * class instance, after initialisation.
82 static dmhTypeGeneric *dmh = NULL;
84 #define client GetModuleHandle( NULL )
85 static inline dmhTypeGeneric *dmh_init_gui( const char *progname )
87 /* Stub function to support run-time binding of a client-provided
88 * implementation for the DMH_SUBSYSTEM_GUI class methods.
90 typedef dmhTypeGeneric *(*init_hook)( const char * );
91 init_hook do_init = (init_hook)(GetProcAddress( client, "dmh_init_gui" ));
92 return do_init ? do_init( progname ) : NULL;
95 EXTERN_C void dmh_init( const dmh_class subsystem, const char *progname )
97 /* Public entry point for message handler initialisation...
99 * We only do it once, silently ignoring any attempt to
100 * establish a second handler.
104 /* No message handler has yet been initialised;
105 * passing the specified program name, select...
107 if( (subsystem == DMH_SUBSYSTEM_GUI)
109 * ...a GUI class handler on demand...
111 && ((dmh = dmh_init_gui( progname )) == NULL) )
113 * ...but bail out, if this cannot be initialised...
115 throw dmh_exception( "DMH subsystem initialisation failed" );
118 /* ...otherwise, a console class handler by default.
120 dmh = new dmhTypeTTY( progname );
125 int abort_if_fatal( const dmh_severity code, int status )
127 /* Helper function to abort an application, on notification
128 * of a DMH_FATAL exception.
130 if( code == DMH_FATAL )
131 throw dmh_exception( "Fatal error occured" );
133 /* If the exception wasn't DMH_FATAL, then fall through to
134 * return the specified status code.
139 uint16_t dmhTypeTTY::control( const uint16_t request, const uint16_t mask )
141 /* Select optional features of the console class message handler.
142 * This message handler provides no optional features; we make this
148 inline int dmhTypeTTY::emit_and_flush( int status )
150 /* Users of MSYS terminal emulators, in place of the standard
151 * MS-Windows console, may experience an I/O buffering issue on
152 * stderr (?!!) which may result in apparently erratic delivery
153 * of progress reporting diagnostics; this may lead to a false
154 * impression that mingw-get has stalled. This inline wrapper
155 * ensures that any buffer which is improperly associated with
156 * stderr is flushed after each message is posted; this may
157 * mitigate the improper buffering issue.
163 int dmhTypeTTY::notify( const dmh_severity code, const char *fmt, va_list argv )
165 /* Message dispatcher for console class applications.
167 static const char *severity[] =
169 /* Labels to identify message severity...
171 "INFO", /* DMH_INFO */
172 "WARNING", /* DMH_WARNING */
173 "ERROR", /* DMH_ERROR */
174 "FATAL" /* DMH_FATAL */
177 /* Dispatch the message to standard error, terminate application
178 * if DMH_FATAL, else continue, returning the message length.
180 return abort_if_fatal( code,
182 fprintf( stderr, "%s: *** %s *** ", progname, severity[code] )
183 + vfprintf( stderr, fmt, argv )
188 int dmhTypeTTY::printf( const char *fmt, va_list argv )
190 /* Display arbitrary text messages via the diagnostic message handler;
191 * for the TTY subsystem, this is equivalent to printf() on stderr.
193 return emit_and_flush( vfprintf( stderr, fmt, argv ) );
196 EXTERN_C uint16_t dmh_control( const uint16_t request, const uint16_t mask )
198 return dmh->control( request, mask );
201 EXTERN_C int dmh_notify( const dmh_severity code, const char *fmt, ... )
203 /* Public entry point for diagnostic message dispatcher.
207 /* The message handler has been called before initialising it;
208 * this is an internal program error -- treat it as fatal!
210 dmh_init( DMH_SUBSYSTEM_TTY, "dmh" );
211 dmh_notify( DMH_FATAL, "message handler was not initialised\n" );
214 /* Normal operation; pass the message on to the active handler.
217 va_start( argv, fmt );
218 int retcode = dmh->notify( code, fmt, argv );
223 EXTERN_C int dmh_printf( const char *fmt, ... )
225 /* Simulate standard printf() function calls, redirecting the display
226 * of formatted output through the diagnostic message handler.
229 va_start( argv, fmt );
230 int retcode = dmh->printf( fmt, argv );
235 /* $RCSfile$: end of file */