[b70b9b]: src / dmh.cpp  Maximize  Restore  History

Download this file

266 lines (237 with data), 7.8 kB

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

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks