File Coverage

blib/lib/Win32/GUI/Carp.pm
Criterion Covered Total %
statement 56 110 50.9
branch 14 52 26.9
condition 6 18 33.3
subroutine 13 19 68.4
pod 4 7 57.1
total 93 206 45.1


line stmt bran cond sub pod time code
1             package Win32::GUI::Carp;
2              
3 1     1   43333 use strict;
  1         3  
  1         285  
4             require 5.005;
5              
6 1     1   9 use vars qw/$VERSION/;
  1         2  
  1         77  
7             $VERSION='1.01';
8              
9 1     1   7 use Exporter;
  1         7  
  1         40  
10 1     1   21 use Carp;
  1         2  
  1         121  
11 1     1   1904 use IPC::Open3;
  1         10282  
  1         66  
12              
13 1     1   10 use vars qw/@ISA @EXPORT @EXPORT_FAIL @EXPORT_OK/;
  1         2  
  1         94  
14             @ISA = qw(Exporter);
15             @EXPORT = qw(confess croak carp); # from Carp (also cluck)
16             @EXPORT_FAIL = qw(
17             fatalsToDialog
18             warningsToDialog
19             immediateWarnings
20             );
21             @EXPORT_OK = (@EXPORT_FAIL, qw/ cluck windie winwarn syscarp syscroak /);
22              
23 1     1   4 use vars qw/@WARNINGS/;
  1         1  
  1         32  
24              
25 1         99 use vars qw/
26             $ImmediateWarnings
27             $FatalsToDialog
28             $WarningsToDialog
29             $DialogTitle
30             $DefaultWarnTitle
31             $DefaultDieTitle
32             $FatalFilter
33             $WarningFilter
34 1     1   5 /;
  1         1  
35             $DialogTitle = '';
36             $DefaultWarnTitle = 'Warning';
37             $DefaultDieTitle = 'Error';
38             $FatalFilter = undef;
39             $WarningFilter = undef;
40              
41 1     1   4 use vars qw/$OLDDIE $OLDWARN/; # play nice with others
  1         2  
  1         1044  
42             $OLDDIE = $SIG{__DIE__}; $SIG{__DIE__} = \&death;
43             $OLDWARN = $SIG{__WARN__}; $SIG{__WARN__} = \&warned;
44              
45             # handle special directives... well, specially
46             sub export_fail {
47 0     0 0 0 my $pkg = shift;
48 0         0 my @unknown;
49              
50 0         0 for my $failed (@_) {
51 0 0       0 if ($failed eq 'fatalsToDialog') { $FatalsToDialog = 1 }
  0 0       0  
    0          
52 0         0 elsif($failed eq 'warningsToDialog') { $WarningsToDialog = 1 }
53 0         0 elsif($failed eq 'immediateWarnings') { $ImmediateWarnings = 1 }
54 0         0 else { push @unknown, $failed }
55             }
56              
57 0         0 return @unknown;
58             }
59              
60             sub windie {
61 0     0 1 0 local $FatalsToDialog = 1;
62 0 0 0     0 if($#_ or $_[0] =~ /\n/) {
63 0         0 die @_;
64             } else {
65 0         0 croak @_;
66             }
67             }
68              
69             sub death {
70 4     4 0 7053 eval {
71             # save any warnings in @new_warns
72 4         23 local $SIG{__WARN__} = \&warned;
73 4 50       23 $OLDDIE->(@_) if($OLDDIE); # invoke the old handler
74             };
75              
76 4 50       13 if($@) { @_ = ($@) } # check for death in old handler; use as new message
  0         0  
77              
78 4 100 33     25 if($FatalsToDialog and not ($FatalFilter and not $FatalFilter->(@_))) {
      66        
79 1         3 local $DialogTitle = $DialogTitle;
80 1 50       7 $DialogTitle = $DefaultDieTitle if($DialogTitle eq '');
81              
82 1         8 dodialog(@WARNINGS, @_); # show message and any pending warnings
83 1         6 @WARNINGS = (); # remove warnings so they're not accidentally shown twice
84             }
85              
86 4         35 die(@_);
87             }
88              
89             sub winwarn {
90 0     0 1 0 local $WarningsToDialog = 1;
91 0 0 0     0 if($#_ or $_[0] =~ /\n/) {
92 0         0 warn @_;
93             } else {
94 0         0 carp @_;
95             }
96             }
97              
98             sub warned {
99 2     2 0 2541 my @new_warns;
100              
101 2         6 eval {
102 2     2   21 local $SIG{__WARN__} = sub { push @new_warns, [@_] };
  2         35  
103 2         12 local $SIG{__DIE__}; # suppress handlers; we propagate any death later
104 2 50       42 $OLDWARN->(@_) if($OLDWARN); # invoke the old handler
105             };
106 2         5 my $oldwarn_death = $@; # get warnings out of the way first
107              
108 2 50       11 if(@new_warns) { @_ = @new_warns } # look for warnings from handler...
  2 0       7  
109 0         0 elsif($OLDWARN) { return } # if none, and there _is_ a handler,
110 0         0 else { @_ = [@_] } # we have to suppress this warning,
111             # since that's what would happen if
112             # we weren't here to notice
113              
114 2 100 33     21 if($WarningsToDialog and not ($WarningFilter and not $WarningFilter->(@_))) {
      66        
115 1         758 local $DialogTitle = $DialogTitle;
116 1 50       7 $DialogTitle = $DefaultWarnTitle if($DialogTitle eq '');
117              
118 1 50       5 if($ImmediateWarnings) {
119 1         8 dodialog(@$_) for(@_);
120             } else {
121 0         0 push @WARNINGS, @$_ for(@_);
122             }
123             }
124              
125 2         274 warn(@$_) for(@_);
126 2 50       21 die($oldwarn_death) if($oldwarn_death); # propagate any death
127             }
128              
129             sub syscarp {
130 0     0 1   my $cmd = shift;
131 0           local ($@, $!, $/);
132              
133 0 0         open( OUTPUT, ">&STDOUT" ) or die "Can't dup STDOUT to OUTPUT: $!\n";
134 0 0         open( OUTERR, ">&STDERR" ) or die "Can't dup STDERR to OUTERR: $!\n";
135 0           my ($pid, $val);
136 0           eval {
137 0           $pid = open3("<&STDIN", \*OUTPUT, \*OUTERR, $cmd) ;
138 0           $val = waitpid(-1,0); # <--- added this line
139             };
140 0 0         $@ && die "ERROR: $@\n";
141              
142 0           my $results = ;
143 0           my $errors = ;
144 0           close OUTPUT;
145 0           close OUTERR;
146              
147 0 0         warn $errors if($errors);
148 0           return $results;
149             }
150              
151             sub syscroak {
152 0     0 1   my $cmd = shift;
153 0           local ($@, $!, $/);
154              
155             # This code was mostly stolen from particle on PerlMonks
156             # See: http://perlmonks.org/index.pl?node_id=86540
157 0 0         open( OUTPUT, ">&STDOUT" ) or die "Can't dup STDOUT to OUTPUT: $!\n";
158 0 0         open( OUTERR, ">&STDERR" ) or die "Can't dup STDERR to OUTERR: $!\n";
159 0           my ($pid, $val);
160 0           eval {
161 0           $pid = open3("<&STDIN", \*OUTPUT, \*OUTERR, $cmd) ;
162 0           $val = waitpid(-1,0); # <--- added this line
163             };
164 0 0         $@ && die "syscroak error: $@\n";
165              
166 0           my $results = ;
167 0           my $errors = ;
168 0           close OUTPUT;
169 0           close OUTERR;
170              
171             # Note: There seems to be a bug on *some* versions of Win32
172             # where $? is always set to 0 after the waitpid, instead of
173             # the correct return value of the called program. It seems
174             # to be OS dependant, and not Perl build dependant (as it
175             # occurred on one computer w/ Win98 and not on another with
176             # Win2k, though both had the same build of ActiveState Perl).
177 0 0         croak $errors . "(`$cmd` returned " . ($? >> 8) . ")" if($errors);
178              
179 0           return $results;
180             }
181              
182             sub END {
183 1     1   1540 local $DialogTitle = $DialogTitle;
184 1 50       22 $DialogTitle = $DefaultWarnTitle if($DialogTitle eq '');
185 1 50       8 dodialog(@WARNINGS) if(@WARNINGS); # show any pending warnings
186             }
187              
188             sub dodialog {
189 0     0     require Win32::GUI;
190 0           my $msg = join '', @_;
191 0           (Win32::GUI::Window->new(-name=>$DialogTitle))->MessageBox($msg,$DialogTitle)
192             ;
193             }
194              
195             1;
196              
197              
198             =head1 NAME
199              
200             Win32::GUI::Carp - Redirect warnings and errors to Win32::GUI MessageBoxes
201              
202             =head1 SYNOPSIS
203              
204             use Win32::GUI::Carp qw/cluck/;
205              
206             croak "Ribbit!";
207             confess "It was me: $!";
208             carp "How could you do that?";
209             warn "Duck!";
210             die "There's no hope...";
211             cluck "Don't do it.";
212              
213             use Win32::GUI::Carp qw/warningsToDialog/;
214             warn "Warnings will be displayed in a pop-up dialog.";
215              
216             use Win32::GUI::Carp qw/fatalsToDialog/;
217             die "Fatal error messages will be displayed in a pop-up dialog.";
218              
219             use Win32::GUI::Carp qw/winwarn windie/;
220             winwarn "Warning in dialog.";
221             windie "Death in dialog.";
222              
223             =head1 DESCRIPTION
224              
225             When Perl programs are run in a GUI environment, it is often
226             desirable to have them run with no console attached.
227             Unfortunately, this causes any warnings or errors to be
228             lost. Worse, fatal errors can cause your program to
229             silently disappear, forcing you to restart the program,
230             attached to a console, and hope you can reproduce the error.
231              
232             This module makes it easy to see any errors or warnings your
233             console-less program might produce by catching any errors
234             and/or warnings and displaying them in a pop-up dialog box
235             using Win32::GUI. It is similar in spirit to CGI::Carp's
236             C and C special import
237             directives.
238              
239             To cause errors or warnings to be displayed in a dialog,
240             simply specify one or more of the following options on the
241             C line, as shown in the L.
242              
243             =head1 IMPORT OPTIONS
244              
245             =head2 C
246              
247             Show any warnings in a pop-up dialog box.
248              
249             This option will cause a dialog box to be displayed
250             containing the text of the warnings. The type and style of
251             the dialog box can be configured (see L<"CONFIGURATION">).
252             Note that warnings are still sent to C as well.
253              
254             This option can also be activated or deactivated by setting
255             C<$Win32::GUI::Carp::WarningsToDialog> to true or false,
256             respectively.
257              
258             =head2 C
259              
260             Show any fatal errors in a pop-up dialog box.
261              
262             This option will cause a dialog box to be displayed
263             containing the text of the fatal error. The type and style
264             of the dialog box can be configured (see
265             L<"CONFIGURATION">). Note that errors are still sent to
266             C as well.
267              
268             This option can also be activated or deactivated by setting
269             C<$Win32::GUI::Carp::FatalsToDialog> to true or false,
270             respectively.
271              
272             =head2 C
273              
274             This option controls whether all errors and warnings are
275             displayed in a single dialog box or each get their own.
276              
277             By default, warnings are buffered and not shown until just
278             before the program terminates. At that point, any warnings
279             and errors are shown together in a single dialog box. This
280             is to cut down on the number of dialogs that have to be
281             clicked through, although it means that you can't tell when
282             a particular warning occurred.
283              
284             If this option is specified, each warning and error message
285             will get its own dialog box which will be displayed as soon
286             as the warning or error occurs. Note that warnings are
287             always printed to C as soon as they occur,
288             regardless of the state of this option.
289              
290             Care should be taken when setting this option as it can
291             cause a large number of dialog boxes to be created.
292              
293             This option can also be activated or deactivated by setting
294             C<$Win32::GUI::Carp::ImmediateWarnings> to true or false,
295             respectively.
296              
297             =head1 FUNCTIONS
298              
299             =head2 C
300              
301             Raises a warning, using a dialog. This function ignores the
302             state of C, although all other options are
303             observed (including ImmediateWarnings).
304              
305             =head2 C
306              
307             Raises a fatal error, using a dialog. This function ignores
308             the state of C, although all other options
309             are observed.
310              
311             =head2 C
312              
313             Executes a system command, just like L, but passes
314             its its STDERR through any warn filters. In other words, if
315             the command displays anything on STDERR, it will show up as
316             a warning in the calling program, and thus display in a
317             dialog (respecting warningsToDialog).
318              
319             Note: The name of this function is subject to change, as I
320             think it is somewhat misleading.
321              
322             =head2 C
323              
324             Does the same thing as L<"syscarp"> but dies if anything is
325             sent to STDERR. It includes a message with the return value
326             of the process.
327              
328             Note: The name of this function is subject to change, as I
329             think it is somewhat misleading.
330              
331             =head1 CONFIGURATION
332              
333             The following variables control the style and type of dialog
334             box used.
335              
336             =head2 C<$Win32::GUI::Carp::DialogTitle>
337              
338             A string that will be used as the title of the dialog box.
339             This defaults to "Warning" when displaying warnings, and
340             "Error" when displaying fatal errors.
341              
342             =head2 C<$Win32::GUI::Carp::FatalFilter>
343              
344             Set this to a reference to a subroutine that should be
345             called whenever a fatal error is about to be shown in a
346             dialog. The routine receives the error message in C<@_>,
347             and if it returns a true value the error will be sent
348             to the dialog as normal, otherwise the dialog will not
349             be shown (though the error still propagates as normal).
350              
351             =head2 C<$Win32::GUI::Carp::WarningFilter>
352              
353             Set this to a reference to a subroutine that should be
354             called whenever a warning is about to be shown in a
355             dialog. The routine receives the warning message in
356             C<@_>, and if it returns a true value the warning will
357             be sent to the dialog as normal, otherwise the dialog
358             will not be shown (though the warning still propagates
359             as normal).
360              
361             =head1 DEPENDANCIES
362              
363             This module relies on the following other modules to be
364             installed:
365              
366             =over 4
367              
368             =item Win32::GUI
369              
370             =item Carp
371              
372             =item IPC::Open3 (for L<"syscarp"> and L<"syscroak">)
373              
374             =back
375              
376             =head1 BUGS
377              
378             =over 4
379              
380             =item *
381              
382             This module installs a signal handler for both C<__DIE__>
383             and C<__WARN__>. While it does save any previous handlers
384             and chain them properly, any new handler that is installed
385             will effectively disable the C and
386             C options, respectively. Note that, as
387             this module's handlers are installed at compile time, it is
388             probable that I other handlers will be "new."
389              
390             Especially if these changes aren't properly localized, this
391             can cause us to miss many errors. There is a work-around,
392             but it's a bit of an ugly hack, and involves tying %SIG,
393             which seems dangerous. I may include it as an option in the
394             future.
395              
396             =item *
397              
398             By default, C, C and C are
399             exported from C. If nothing is specified in the
400             import list (including the special C<*ToDialog> and
401             C options), then C also
402             exports those functions. As soon as I is given in
403             the import list, however, C stops exporting the
404             things in C<@EXPORT> (meaning the aforementioned functions
405             don't get exported).
406              
407             =item *
408              
409             There seems to be a bug on I versions of Win32
410             affecting L<"syscarp"> and, moreso, L<"syscroak"> where $?
411             is always set to 0, instead of the correct return value of
412             the called program.
413              
414             =back
415              
416             =head1 AUTHOR
417              
418             Copyright 2002, Cory Johns.
419              
420             This module is free software; you can redistribute and/or
421             modify it under the same terms as Perl itself.
422              
423             Address bug reports and comments to:
424             Cory Johns ELE
425              
426             =head1 SEE ALSO
427              
428             Carp, CGI::Carp, Win32::GUI
429              
430             =cut
431