Christopher Spears wrote:
I've been learning C++ using cygwin on my Windows PC
and thought it would be handy to have a Perl script
that automated features of g++.  The script takes one
to two invocation arguments:

./cedit somefile.C++
./cedit somefile.C++ outputfile

cedit runs g++. After the file is compiled,etc., any
error messages are stored in a text file called
"caught_error". cedit then opens caught_error, reads
its contents, and displays the contents to the user. I did this so I could cut and paste error messages
from the file using a text editor. cedit then asks
the user if s/he would like to launch vi. If the user
selects "yes", s/he is given the option of entering a
line number. After entering the line number, vi
starts up and opens somefile.C++ and caught_error. In
somefile.C++, the cursor should be at the line
designated by the user. If the user did not designate
a line, vi would just start and open the two files.



SOme of these remarks are more Perlish style than programming necessities, coming from a C++ background they are pretty common. Otherwise most of it looks fine to me.



#!/bin/perl -w use strict;


The above is the best part of the script :-).

sub choose_vi {
    print "Use vi?\n";
    print "Y/y for yes.  Any other key quits: ";
    chomp(my $answer = <STDIN>);
    if ($answer =~ /^[yY]$/) {

The above regex could be written without the character class and using the 'i' switch for case insensitivity. This seems like a nit-pick but in the coming age of unicode that can start to matter.... sometimes it is convention to just check the starting character rather than ^ and $, this allows a user to enter 'y','Y','yes','Yes','YES','yEs', etc. as long as the first character is some incantation of 'y'.


/^y/i

Shorter too if you're one of those kind...

print "Enter line number? (Y for yes):";
chomp(my $answer = <STDIN>);
print "\n";
if ($answer =~ /^[yY]$/) {
print "Enter line number: ";
chomp(my $line_number = <STDIN>); system "vi", "+".$line_number, $ARGV[0],
"caught_errors";

Since this is a user interactive script it probably doesn't matter, but you should usually check to see if system failed to run the command, and/or what it returns. From a security standpoint you should use a full path to the called command, but again it probably is ok in this situation.


} else {
system "vi", $ARGV[0], "caught_errors";
} } else {
print "Goodbye!\n";
}
}


sub read_ce {
   print "Errrors:\n";        
   open CAUGHT, "caught_errors" or die "Can't open
file: $!";
   my @lines= readline(CAUGHT);

If this is working good, if not you may need to make the above a specific typeglob with '*CAUGHT'. You could also drop the specific call to 'readline' and just use the more Perlish,


my @lines = <CAUGHT>;

my $number_lines = scalar @lines;

'scalar' is uneeded in teh above, but doesn't hurt to have. The temp variable isn't need either since you only appear to use the number of lines once in your loop, and you can just put @lines in scalar context in the loop.


for (my $i = 0; $i < $number_lines; $i++) {

for (my $i = 0; $i < @lines; $i++) {

print $lines[$i];
}

Or you could scrap the whole C style loop and use the much more Perlish,

for my $line (@lines) {
    print $line;
}

Or better yet, save the memory and don't read the whole file in.

while (my $line = <CAUGHT>) {
  print $line;
}

Or if you really want to be Perlish, you can use the implicit $_.

print while (<CAUGHT>);


close CAUGHT;
}


my $number_of_args = @ARGV;

open STDERR, ">./caught_errors" or die "Can't create
caught_errors: $!";

if ($number_of_args == 0) {
print "Not enough arguments!\n";
print "Usage: ./cedit somefile.C++\n";
print "Usage (optional): ./cedit somefile.C++
outputfile\n";
} elsif ($number_of_args == 1) {
system "g++", $ARGV[0];
&read_ce;
&choose_vi;

This is the one thing I would definitely change. In general you should not call functions with an '&' until you know why you need to. They are better written as:


read_ce();
choose_vi();

You are implicitly passing arguments to the functions that you don't intend, this could haunt you later.

} elsif ($number_of_args == 2) {
    system "g++", $ARGV[0], "-o", $ARGV[1];
    &read_ce;
    &choose_vi;
} else {
    print "Too many arguments!\n";
    print "Usage: ./cedit somefile.C++\n";
    print "Usage (optional): ./cedit somefile.C++
outputfile\n";
}




When you get more complex command line arguments you may want to use the Getopt::Std and Getopt::Long modules to parse them, they also provide easily usage handling with Pod::Usage, and example can be found on my website here:


http://danconia.org/cgi-bin/request?handler=Content;content=StaticPage;label=getopt_long_template

Good luck, excellent start,

http://danconia.org

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>




Reply via email to