Can't locate CGIBook/Error.pm - macos

I am new to perl. I am running a perl script on macbook and i get following error:
Can't locate CGIBook/Error.pm in #INC (#INC contains: /Library/Perl/5.12/darwin-thread-
multi-2level /Library/Perl/5.12 /Network/Library/Perl/5.12/darwin-thread-multi-2level
/Network/Library/Perl/5.12 /Library/Perl/Updates/5.12.3 /System/Library/Perl/5.12/darwin-
thread-multi-2level /System/Library/Perl/5.12 /System/Library/Perl/Extras/5.12/darwin-
thread-multi-2level /System/Library/Perl/Extras/5.12) at HW1_3A.pl line 5.
It looks like I don't have CGIBook in my perl directory. Is that correct? Can anyone help me with this?

I didn't find CGIBook::Error on CPAN, so it may be a local module or something you got (or should get) from a vendor. Someone may have installed in a different location other than the default module search path.
In this case, it looks like you may be trying to use an example from the ancient book CGI Programming with Perl, which created a module with the same name for the examples.
A Google search of the error message quickly led to this code:
#!/usr/bin/perl -wT
package CGIBook::Error;
# Export the error subroutine
use Exporter;
#ISA = "Exporter";
#EXPORT = qw( error );
$VERSION = "0.01";
use strict;
use CGI;
use CGI::Carp qw( fatalsToBrowser );
BEGIN {
sub carp_error {
my $error_message = shift;
my $q = new CGI;
my $discard_this = $q->header( "text/html" );
error( $q, $error_message );
}
CGI::Carp::set_message( \&carp_error );
}
sub error {
my( $q, $error_message ) = #_;
print $q->header( "text/html" ),
$q->start_html( "Error" ),
$q->h1( "Error" ),
$q->p( "Sorry, the following error has occurred: " ),
$q->p( $q->i( $error_message ) ),
$q->end_html;
exit;
}
1;

Related

Perl DBD::CSV No such file or directory on Windows

I must migrate my perlscripts to a new machine but DBD::CSV would not work as I expect.
I got ActiveState perl 5, version 16, subversion 3 (v5.16.3) built for MSWin32-x86-multi-thread
DBD-CSV is Version 0.41 and everyting I try results in:
#################################################################
DBD::CSV::db do failed:
Execution ERROR: -d D:\TEST/D:\TEST: No such file or directory at D:/Programme/Perl/site/lib/DBI/DBD/SqlEngine.pm line 1503.
called from D:\TEST\CSVTest.pl at 7.
#################################################################
even at the simplest create TestTable
#################################################################
use DBI;
$dbh = DBI->connect ("dbi:CSV:");
my $table ="TestTable";
$dbh->do ("CREATE TABLE $table (id INTEGER, name CHAR (64))");
#################################################################
Any suggestion?
Update
Not the real answer, but too much for an comment the uncommented $DBDIR is the way i had excpeted to work. All the commented versions of $DBDIR I tried, but all created an foo.csv in same directory as the script (C:\Temp). I want to use some other Directory as the Script is located any sugestion?
use DBI;
my $DBDIR='C:\Temp\CSV-DB';
# my $DBDIR="C:\\Temp\\CSV-DB";
# my $DBDIR='C:\Temp\CSV-DB\\';
# my $DBDIR='..\CSV-DB';
# my $DBDIR="..\\CSV-DB";
# my $DBDIR='CSV-DB';
# my $DBDIR='\CSV-DB';
# my $DBDIR='\\CSV-DB';
# my $DBDIR='.\CSV-DB';
# my $DBDIR='/CSV-DB';
# my $DBDIR='./CSV-DB';
$dbh = DBI->connect ("dbi:CSV:", undef, undef, {
f_dir => [$DBDIR],
#f_dir_search => [$DBDIR],
f_ext => ".csv/r",
RaiseError => 1,
}) or die "Cannot connect: $DBI::errstr";
# Simple statements
$dbh->do ("CREATE TABLE foo (id INTEGER, name CHAR (10))");
##############################################################
I had this problem on my windows PC.
I found that it occurred when DBI was not the first module to be used.
By putting "use DBI;" as the first module the problem has disappeared.
I haven't tried to determine exactly which module caused the problem. I'm using CGI, Archive::Zip, POSIX, etc..

Perl module - dist.ini and platform specific prereqs

How can I add conditional prereqs to dist.ini for each platform (Windows/Non windows) I want the module to support?
For example in perl code I could do:
if ( $^0 eq 'MSWin32' ){
require Win32::Foo;
}else{
require Bar::Baz;
}
How do I cater to each system/platform like this in dist.ini so that the proper prereqs are installed via cpan/cpanm?
You can't do it in dist.ini, since an ini file doesn't really have any way to do conditional logic. But one way might be to write your own Dist::Zilla plugin, something like this:
package Dist::Zilla::Plugin::MyPrereqs; # pick a better name
use Moose;
with 'Dist::Zilla::Role::PrereqSource';
sub register_prereqs {
my $self = shift;
my %prereqs;
if ( $^0 eq 'MSWin32' ) {
$prereqs{'Win32::Foo'} = '0.12'; # min. version
} else {
$prereqs{'Bar::Baz'} = '1.43';
}
$self->zilla->register_prereqs( %prereqs );
}
If you generalize this to take some platform-dependent lists of prereqs within dist.ini, it would make a good CPAN release.
Use Dist::Zilla::Plugin::OSPrereqs. For your example it would look like:
[OSPrereqs / MSWin32]
Win32::Foo = 0.12
[OSPrereqs / !MSWin32]
Bar::Baz = 1.43

Perl Image::OCR::Tesseract module on Windows

Anyone out there know of a graceful way to install the "Image::OCR::Tesseract" module on Windows? The module fails to install on Windows via CPAN due to a *NIX only module dependency called "LEOCHARRE::CLI". This module does not seem to be required to run "Image::OCR::Tesseract" itself.
I've managed to get the module working by first manually installing the dependency modules listed in the makefile.pl (except for "LEOCHARRE::CLI") and then by moving the module file to the correct directory structure under "C:\Perl\site\lib\Image\OCR". The final part of getting it to work was to alter the section of code that calls the ImageMagick and Tesseract executables from the command line to put quotes around the program names when the executables are called by module.
This works, but I'd really feel better about doing a PPM or CPAN install on a production system from a repo that works on Windows.
Never mind, I got it, though I can't decide what is the better solution.
To get the installer to work on Windows via the traditional "perl makefile.pl, make, make test, make install" routine requires an edit to the Makefile.pl script, including the missing Windows install module (Devel::AssertOS::MSWin32), and patch to AssertEXE.pm to use "File::Which" rather than the built in shell "which" command that Windows lacks. All this still requires that The "Image::OCR::Tesseract" be patched to put quotes around program names when executing "convert" and "tesseract" from the command line.
Given the number of steps involved to make the installer work on Windows, and the fact the module does not create a binary component for the module to link to, I'd say the best option for installing and getting the Tesseract module working on windows would be to first install the following binary packages:
ImageMagick
Link
Tesseract
http://code.google.com/p/tesseract-ocr/downloads/list
Next, locate your Perl module directory - on my system it is "C:\Perl\site\lib". Create a folder "Image", if you don't have one. Next, open the Image folder and create a folder called "OCR". Open the OCR folder. At this point, your path should be something along the lines of "C:\Perl\site\lib\Image\OCR". Create a new text file called "Tesseract.pm", and copy in the following content...
package Image::OCR::Tesseract;
use strict;
use Carp;
use Cwd;
use String::ShellQuote 'shell_quote';
use Exporter;
use vars qw(#EXPORT_OK #ISA $VERSION $DEBUG $WHICH_TESSERACT $WHICH_CONVERT %EXPORT_TAGS #TRASH);
#ISA = qw(Exporter);
#EXPORT_OK = qw(get_ocr get_hocr _tesseract convert_8bpp_tif tesseract);
$VERSION = sprintf "%d.%02d", q$Revision: 1.24 $ =~ /(\d+)/g;
%EXPORT_TAGS = ( all => \#EXPORT_OK );
BEGIN {
use File::Which 'which';
$WHICH_TESSERACT = which('tesseract');
$WHICH_CONVERT = which('convert');
if($^O=~m/MSWin/) {
$WHICH_TESSERACT='"'.$WHICH_TESSERACT.'"';
$WHICH_CONVERT='"'.$WHICH_CONVERT.'"';
}
$WHICH_TESSERACT or die("Is tesseract installed? Cannot find bin path to tesseract.");
$WHICH_CONVERT or die("Is convert installed? Cannot find bin path to convert.");
}
END {
scalar #TRASH or return;
if ( $DEBUG ){
print STDERR "Debug on, these are trash files:\n".join("\n",#TRASH) ;
}
else {
unlink #TRASH;
}
}
sub DEBUG { Carp::cluck("Image::OCR::Tesseract::DEBUG() deprecated") }
sub get_hocr {
my ($abs_image,$abs_tmp_dir,$lang)= #_;
-f $abs_image or croak("$abs_image is not a file on disk");
my $hocr="hocr";
if(defined $abs_tmp_dir){
-d $abs_tmp_dir or die("tmp dir arg $abs_tmp_dir not a dir on disk.");
$abs_image=~/([^\/]+)$/ or die("cant match filename in path arg '$abs_image'");
my $abs_copy = "$abs_tmp_dir/$1";
# TODO, what if source and dest are same, i want it to die
require File::Copy;
File::Copy::copy($abs_image, $abs_copy)
or die("cant make copy of $abs_image to $abs_copy, $!");
# change the image to get ocr from to be the copy
$abs_image = $abs_copy;
# since it's a copy. erase that on exit
push #TRASH, $abs_image;
}
my $tmp_tif = convert_8bpp_tif($abs_image);
push #TRASH, $tmp_tif; # for later delete
_tesseract($tmp_tif,$lang,$hocr) || '';
}
sub get_ocr {
my ($abs_image,$abs_tmp_dir,$lang)= #_;
-f $abs_image or croak("$abs_image is not a file on disk");
if(defined $abs_tmp_dir){
-d $abs_tmp_dir or die("tmp dir arg $abs_tmp_dir not a dir on disk.");
$abs_image=~/([^\/]+)$/ or die("cant match filename in path arg '$abs_image'");
my $abs_copy = "$abs_tmp_dir/$1";
# TODO, what if source and dest are same, i want it to die
require File::Copy;
File::Copy::copy($abs_image, $abs_copy)
or die("cant make copy of $abs_image to $abs_copy, $!");
# change the image to get ocr from to be the copy
$abs_image = $abs_copy;
# since it's a copy. erase that on exit
push #TRASH, $abs_image;
}
my $tmp_tif = convert_8bpp_tif($abs_image);
push #TRASH, $tmp_tif; # for later delete
_tesseract($tmp_tif,$lang) || '';
}
sub convert_8bpp_tif {
my ($abs_img,$abs_out) = (shift,shift);
defined $abs_img or die('missing image arg');
$abs_out ||= $abs_img.'.tmp.'.time().(int rand(9000)).'.tif';
my #arg = ( $WHICH_CONVERT, $abs_img, '-compress','none','+matte', $abs_out );
#die (join(" ", #arg));
system(#arg) == 0 or die("convert $abs_img error.. $?");
$DEBUG and warn("made $abs_out 8bpp tiff.");
$abs_out;
}
# people expect tesseract to automatically convert
*tesseract = \&_tesseract;
sub _tesseract {
my ($abs_image,$lang,$hocr) = #_;
defined $abs_image or croak('missing image path arg');
$abs_image=~/\.tif+$/i or warn("Are you sure '$abs_image' is a tif image? This operation may fail.");
#my #arg = (
# $WHICH_TESSERACT, shell_quote($abs_image), shell_quote($abs_image),
# (defined $lang and ('-l', $lang) ), '2>/dev/null'
#);
my $cmd =
( sprintf '%s %s %s',
$WHICH_TESSERACT,
shell_quote($abs_image),
shell_quote($abs_image)
) .
( defined $lang ? " -l $lang" : '' ) .
( defined $hocr ? " hocr" : '' ) .
" 2>/dev/null";
$DEBUG and warn "command: $cmd";
system($cmd); # hard to check ==0
my $txt = $abs_image.($hocr?".html":".txt");
unless( -f $txt ){
Carp::cluck("no text output for image '$abs_image'. (No text file '$txt' found on disk)");
return;
}
$DEBUG and warn "Found text file '$txt'";
my $content = (_slurp($txt) || '');
$DEBUG and warn("content length of text in '$txt' from image '$abs_image' is ". length $content );
push #TRASH, $txt;
$content;
}
sub _slurp {
my $abs = shift;
open(FILE,'<', $abs) or die("can't open file for reading '$abs', $!");
local $/;
my $txt = <FILE>;
close FILE;
$txt;
}
1;
__END__
#sub _force_imgtype {
# my $img = shift;
# my $type = shift;
# my $delete_original = shift;
# $delete_original ||=0;
#
#
# if($img=~/\.$type$/i){
# return $img;
# }
#
# my $img_out= $img;
# $img_out=~s/\.\w{1,5}$/\.$type/ or die("cant get file ext for $img");
#
#
#
#}
Save and close. Close the command line session and open a new one if you've had one open from before you did the ImageMagick and Tesseract binary installs. Test the module with the following script:
use Image::OCR::Tesseract;
my $image = 'SomeImageFileThatContainsText.jpg';
my $text = Image::OCR::Tesseract::get_ocr($image);
print "Text...\n";
print $text."\n";
print "Normal Exit\n";
exit;
That's it. Messy, I know, but there's no good way around the fact that the module installer really needs to be updated to support Windows (and other) systems even though the actual module code almost runs without modification. Really, if Tesseract and ImageMagick were installed to paths without spaces then the "Image::OCR::Tesseract" module code would not need any changes, but this minor tweak lets the supporting executables be installed anywhere, including the default locations.

Archive::Any gives IO error

#!/usr/bin/perl
use strict;
use warnings;
my $archive_files = "C:\\Temp\\FREMOTE\\test.zip";
sub extract_archive($$);
extract_archive($archive_files, "C:\\Temp\\FREMOTE\\TEST\\");
extract_archive("C:\\Temp\\FREMOTE\\TEST\\testb.zip",
"C:\\Temp\\FREMOTE\\TEST\\testb\\");
sub extract_archive($$) {
my $archive_file = shift;
my $extract_dir = shift;
if (! -d "$extract_dir") {
mkdir $extract_dir;
}
use Archive::Any;
my $archive = Archive::Any->new($archive_file);
if($archive->extract($extract_dir)) {
print "Extracted $archive_file into $extract_dir\n";
undef $archive;
} else {
print "Failed to extracted $archive_file into $extract_dir\n";
}
}
I got the following error. How do I resolve it?
IO error: write error during copy : Bad file descriptor
at C:/Perl/site/lib/Archive/Any.pm line 193.
IO error: write error during copy : Bad file descriptor
at C:/Perl/site/lib/Archive/Any.pm line 193.
IO error: write error during copy : Bad file descriptor
at C:/Perl/site/lib/Archive/Any.pm line 193.
IO error: write error during copy : Bad file descriptor
at C:/Perl/site/lib/Archive/Any.pm line 193.
I tested it with the following code. Using two known-good zip files, I added the second zip file into the first - to reproduce what I believe you are doing. With the original code I kept receiving an error during the extraction of the second file:
Extracted C:\Temp\colorbox-master.zip into C:\Temp\FREMOTE\TEST\<br>
Can't call method "extract" on an undefined value at Perl-1.pl line 19.
Different from your error, but fixed with the following code:
#!/usr/bin/perl
use strict;
use warnings;
my $archive_files = "C:\\Temp\\colorbox-master.zip";
extract_archive($archive_files, "C:\\Temp\\FREMOTE\\TEST\\");
extract_archive("C:\\Temp\\FREMOTE\\TEST\\easybox-v1.3.zip", "C:\\Temp\\FREMOTE\\TEST\\testb\\");
sub extract_archive {
my $archive_file = shift;
my $extract_dir = shift;
if (!-d "$extract_dir") {
mkdir $extract_dir;
}
use Archive::Any;
my $archive = Archive::Any->new($archive_file);
if($archive->extract($extract_dir)) {
print "Extracted $archive_file into $extract_dir\n";
undef $archive;
} else {
print "Failed to extracted $archive_file into $extract_dir\n";
}
}
Extracted C:\Temp\colorbox-master.zip into C:\Temp\FREMOTE\TEST\
Extracted C:\Temp\FREMOTE\TEST\easybox-v1.3.zip into C:\Temp\FREMOTE\TEST\testb\
Note that I had just installed the 'Archive::Any-0.0932' module (ActiveState Perl) so I may have a different (fixed) version. You may want to check that your module is at the most recent version. And that your zip files are not broken.

How can I open a file found by File::Find from inside the wanted function?

I have code like below. If I open the file $File::Find::name (in this case it is ./tmp/tmp.h) in my search function (called by File::Find::find), it says "cannot open the file ./tmp/tmp.h reason = No such file or directory at temp.pl line 36, line 98."
If I open the file directly in another function, I am able open the file.
Can somebody tell me the reason for this behavior? I am using activeperl on Windows and the version is 5.6.1.
use warnings;
use strict;
use File::Find;
sub search
{
return unless($File::Find::name =~ /\.h\s*$/);
open (FH,"<", "$File::Find::name") or die "cannot open the file $File::Find::name reason = $!";
print "open success $File::Find::name\n";
close FH;
}
sub fun
{
open (FH,"<", "./tmp/tmp.h") or die "cannot open the file ./tmp/tmp.h reason = $!";
print "open success ./tmp/tmp.h\n";
close FH;
}
find(\&search,".") ;
See perldoc File::Find: The wanted function (search in your case) will be called after File::Find::find changed to the directory that is currently searched. As you can see, $File::Find::name contains the path to the file relative to where the search started. That path that won't work after the current directory changes.
You have two options:
Tell File::Find to not change to the directories it searches: find( { wanted => \%search, no_chdir => 1 }, '.' );
Or don't use $File::Find::name, but $_ instead.
If ./tmp/ is a symbolic link then you will need to do following:
find( { wanted => \&search, follow => 1 }, '.' );
Does that help?
If you want to search the file in current working dir you can use Cwd.
use warnings;
use strict;
use File::Find;
use Cwd;
my $dir = getcwd;
sub search
{
return unless($File::Find::name =~ /\.h\s*$/);
open (FH,"<", "$File::Find::name") or die "cannot open the file $File::Find::name reason = $!";
print "open success $File::Find::name\n";
close FH;
}
find(\&search,"$dir") ;

Resources