Here is a little project I'd like a bit of feedback on.
Not to long ago Anony put up this node. It was a little frusterating to watch. Not only was the mistake a common, simple one, but little niggles of system got even BrowserUK. And frankly, who hasn't been bit by it, once or twice, early in their Perl career?
Another niggle is Perl's error vars. Which one to use, when? And, though system calls are rarely portable, almost no one ever remembers to mention $^E on the off chance that the asker is on a VMS, Win32, or OS/2 system.
Both these issues are tidied up in Perl 6. But who wants to wait that long?
So, Shell::DWIM is intended to clean up these little niggles in a consistent way. I hope that it gets itself established enough that we can all point to it whenever a similar question comes down the pipeline. First, a little documentation, as none is currently supplied.
Shell::DWIM currently has no export system, in order to keep things simple for me. It provides two features.
- Shell::DWIM::run - This function is a RWIM (return what I mean) replacement for system. It returns true for a succesful execution, false for a failure. It does not support system's indirect object features currently. Unlike system it captures the exception generated by passing it tainted data, and sets $Shell::DWIM::RUN_ERROR appropriately.
- $Shell::DWIM::RUN_ERROR - This special variable is set by calls to Shell::DWIM::run. It attempts to be whichever of the four Perl error variables you need, with a few caveats. First, it does not have the number/string magic of $! - it is always stringified. Second, it prefers extended OS errors to the C errno on systems that have extended error support (currently VMS, OS/2, and Win32).
Suggested use:
Shell::DWIM::run $shell_commands or die $Shell::DWIM::RUN_ERROR;
What I ask of the Monastery is a code review and comment. Here are my specific concerns (there are several):
- run and $RUN_ERROR are terrible names - anyone have better ideas?
- Currently run traps the exception caused by system $tainted_data. Should it?
- On the same note, it localizes $@ anticipating that no one will expect the eval{} that run uses internally. Since the other error vars are set correctly, is this application of the Principle of Least Surprise a bit too waterbed like?
- While there is little that goes on that might be suspect, there is a bit of code between system @_ and the use of $! and $^E (called $OS_ERROR internally). perlvar warns that $! should be used immediatly. Is there a danger there?
- If $^E is supported, we use it instead of $!. Is this gonna bite anyone in the butt?
- With a little case specific aliasing, $RUN_ERROR could be made to support $! special magic. But then it could be reset by things other than calls to run. What's your opinion?
- And finally, How's My Hacking? I'm a bit of a hobbyist programmer, so my style hasn't really gelled yet. Is there anything grossly stupid in the code?
Speaking of which:
package Shell::DWIM;
use warnings;
use strict;
our ($EVAL_ERROR, $CHILD_ERROR, $OS_ERROR, $RUN_ERROR);
#Setup internal friendly error names
*EVAL_ERROR = \$@;
*CHILD_ERROR = \$?;
if ($^O =~ /VMS|MSWin|OS\/2/) { #These systems support an extended OS
+error message ($^E)
*OS_ERROR = \$^E; #$OS_ERROR reflects that value if it e
+xists. This clashes somwhat with English.pm
}
else {
*OS_ERROR = \$!;
}
#The public function
sub run {
my ($return) = 0;
local $EVAL_ERROR; #The eval here is a little unexpected, so we lo
+calize $EVAL_ERROR so no one get's bitten
eval {
$return = (( system @_ ) == 0);
};
if ($return) {
$RUN_ERROR = undef;
}
else {
SWITCH: {
do { $RUN_ERROR = $EVAL_ERROR && last SWITCH } if $EVAL_E
+RROR ;
do { $RUN_ERROR = $CHILD_ERROR && last SWITCH } if $CHILD_
+ERROR > 0 ;
do { $RUN_ERROR = "$OS_ERROR" && last SWITCH } if $CHILD_
+ERROR == -1; #String version of $OS_ERROR
LAST_CASE: { $RUN_ERROR =
"Exception, package CommandLine: system() fai
+led, error unknown"}
}
}
return $return;
}
1; #Because you gotta
Cheers,
Erik
Light a man a fire, he's warm for a day. Catch a man on fire, and he's warm for the rest of his life. - Terry Pratchet
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.