diff options
| author | fukachan <fukachan> | 2001-09-24 02:55:28 +0000 |
|---|---|---|
| committer | fukachan <fukachan> | 2001-09-24 02:55:28 +0000 |
| commit | 92e21ffd3554016337d0c0dd3207a58090b22887 (patch) | |
| tree | b8f5bfa475ed60773a27a2b3adf41b7896576669 /cpan | |
| parent | 69784352d8270419ec5395543c5f6f0f0d5dcdc3 (diff) | |
| download | fml8-92e21ffd3554016337d0c0dd3207a58090b22887.tar.gz fml8-92e21ffd3554016337d0c0dd3207a58090b22887.tar.bz2 fml8-92e21ffd3554016337d0c0dd3207a58090b22887.zip | |
Initial revision
Diffstat (limited to 'cpan')
| -rw-r--r-- | cpan/dist/Text-CSV/CSV.pm | 488 | ||||
| -rw-r--r-- | cpan/dist/Text-CSV/MANIFEST | 5 | ||||
| -rw-r--r-- | cpan/dist/Text-CSV/Makefile.PL | 7 | ||||
| -rw-r--r-- | cpan/dist/Text-CSV/README | 32 | ||||
| -rw-r--r-- | cpan/dist/Text-CSV/test.pl | 131 | ||||
| -rw-r--r-- | cpan/lib/Text/CSV.pm | 488 |
6 files changed, 1151 insertions, 0 deletions
diff --git a/cpan/dist/Text-CSV/CSV.pm b/cpan/dist/Text-CSV/CSV.pm new file mode 100644 index 00000000..bb03b2a0 --- /dev/null +++ b/cpan/dist/Text-CSV/CSV.pm @@ -0,0 +1,488 @@ +package Text::CSV; + +# Copyright (c) 1997 Alan Citterman. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +################################################################################ +# HISTORY +# +# Written by: +# Alan Citterman <alan@mfgrtl.com> +# +# Version 0.01 06/05/1997 +# original version +################################################################################ + +require 5.002; + +use strict; + +BEGIN { + use Exporter (); + use AutoLoader qw(AUTOLOAD); + use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + $VERSION = '0.01'; + @ISA = qw(Exporter AutoLoader); + @EXPORT = qw(); + @EXPORT_OK = qw(); + %EXPORT_TAGS = qw(); +} + +1; + +__END__ + +################################################################################ +# version +# +# class/object method expecting no arguments and returning the version number +# of Text::CSV. there are no side-effects. +################################################################################ +sub version { + return $VERSION; +} + +################################################################################ +# new +# +# class/object method expecting no arguments and returning a reference to a +# newly created Text::CSV object. +################################################################################ +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = {}; + $self->{'_STATUS'} = undef; + $self->{'_ERROR_INPUT'} = undef; + $self->{'_STRING'} = undef; + $self->{'_FIELDS'} = undef; + bless $self, $class; + return $self; +} + +################################################################################ +# status +# +# object method returning the success or failure of the most recent combine() +# or parse(). there are no side-effects. +################################################################################ +sub status { + my $self = shift; + return $self->{'_STATUS'}; +} + +################################################################################ +# error_input +# +# object method returning the first invalid argument to the most recent +# combine() or parse(). there are no side-effects. +################################################################################ +sub error_input { + my $self = shift; + return $self->{'_ERROR_INPUT'}; +} + +################################################################################ +# string +# +# object method returning the result of the most recent combine() or the +# input to the most recent parse(), whichever is more recent. there are no +# side-effects. +################################################################################ +sub string { + my $self = shift; + return $self->{'_STRING'}; +} + +################################################################################ +# fields +# +# object method returning the result of the most recent parse() or the input +# to the most recent combine(), whichever is more recent. there are no +# side-effects. +################################################################################ +sub fields { + my $self = shift; + if (ref($self->{'_FIELDS'})) { + return @{$self->{'_FIELDS'}}; + } + return undef; +} + +################################################################################ +# combine +# +# object method returning success or failure. the given arguments are +# combined into a single comma-separated value. failure can be the result of +# no arguments or an argument containing an invalid character. side-effects +# include: +# setting status() +# setting fields() +# setting string() +# setting error_input() +################################################################################ +sub combine { + my $self = shift; + my @part = @_; + $self->{'_FIELDS'} = \@part; + $self->{'_ERROR_INPUT'} = undef; + $self->{'_STATUS'} = 0; + $self->{'_STRING'} = ''; + my $column = ''; + my $combination = ''; + my $skip_comma = 1; + if ($#part >= 0) { + + # at least one argument was given for "combining"... + for $column (@part) { + if ($column =~ /[^\t\040-\176]/) { + + # an argument contained an invalid character... + $self->{'_ERROR_INPUT'} = $column; + return $self->{'_STATUS'}; + } + if ($skip_comma) { + + # do not put a comma before the first argument... + $skip_comma = 0; + } else { + + # do put a comma before all arguments except the first argument... + $combination .= ','; + } + $column =~ s/\042/\042\042/go; + $combination .= "\042"; + $combination .= $column; + $combination .= "\042"; + } + $self->{'_STRING'} = $combination; + $self->{'_STATUS'} = 1; + } + return $self->{'_STATUS'}; +} + +################################################################################ +# parse +# +# object method returning success or failure. the given argument is expected +# to be a valid comma-separated value. failure can be the result of +# no arguments or an argument containing an invalid sequence of characters. +# side-effects include: +# setting status() +# setting fields() +# setting string() +# setting error_input() +################################################################################ +sub parse { + my $self = shift; + $self->{'_STRING'} = shift; + $self->{'_FIELDS'} = undef; + $self->{'_ERROR_INPUT'} = $self->{'_STRING'}; + $self->{'_STATUS'} = 0; + if (!defined($self->{'_STRING'})) { + return $self->{'_STATUS'}; + } + my $keep_biting = 1; + my $palatable = 0; + my $line = $self->{'_STRING'}; + if ($line =~ /\n$/) { + chop($line); + if ($line =~ /\r$/) { + chop($line); + } + } + my $mouthful = ''; + my @part = (); + while ($keep_biting and ($palatable = $self->_bite(\$line, \$mouthful, \$keep_biting))) { + push(@part, $mouthful); + } + if ($palatable) { + $self->{'_ERROR_INPUT'} = undef; + $self->{'_FIELDS'} = \@part; + } + return $self->{'_STATUS'} = $palatable; +} + +################################################################################ +# _bite +# +# *private* class/object method returning success or failure. the arguments +# are: +# - a reference to a comma-separated value string +# - a reference to a return string +# - a reference to a return boolean +# upon success the first comma-separated value of the csv string is +# transferred to the return string and the boolean is set to true if a comma +# followed that value. in other words, "bite" one value off of csv +# returning the remaining string, the "piece" bitten, and if there's any +# more. failure can be the result of the csv string containing an invalid +# sequence of characters. +# +# from the csv string and +# to be a valid comma-separated value. failure can be the result of +# no arguments or an argument containing an invalid sequence of characters. +# side-effects include: +# setting status() +# setting fields() +# setting string() +# setting error_input() +################################################################################ +sub _bite { + my ($self, $line_ref, $piece_ref, $bite_again_ref) = @_; + my $in_quotes = 0; + my $ok = 0; + $$piece_ref = ''; + $$bite_again_ref = 0; + while (1) { + if (length($$line_ref) < 1) { + + # end of string... + if ($in_quotes) { + + # end of string, missing closing double-quote... + last; + } else { + + # proper end of string... + $ok = 1; + last; + } + } elsif ($$line_ref =~ /^\042/) { + + # double-quote... + if ($in_quotes) { + if (length($$line_ref) == 1) { + + # closing double-quote at end of string... + substr($$line_ref, 0, 1) = ''; + $ok = 1; + last; + } elsif ($$line_ref =~ /^\042\042/) { + + # an embedded double-quote... + $$piece_ref .= "\042"; + substr($$line_ref, 0, 2) = ''; + } elsif ($$line_ref =~ /^\042,/) { + + # closing double-quote followed by a comma... + substr($$line_ref, 0, 2) = ''; + $$bite_again_ref = 1; + $ok = 1; + last; + } else { + + # double-quote, followed by undesirable character (bad character sequence)... + last; + } + } else { + if (length($$piece_ref) < 1) { + + # starting double-quote at beginning of string + $in_quotes = 1; + substr($$line_ref, 0, 1) = ''; + } else { + + # double-quote, outside of double-quotes (bad character sequence)... + last; + } + } + } elsif ($$line_ref =~ /^,/) { + + # comma... + if ($in_quotes) { + + # a comma, inside double-quotes... + $$piece_ref .= substr($$line_ref, 0 ,1); + substr($$line_ref, 0, 1) = ''; + } else { + + # a comma, which separates values... + substr($$line_ref, 0, 1) = ''; + $$bite_again_ref = 1; + $ok = 1; + last; + } + } elsif ($$line_ref =~ /^[\t\040-\176]/) { + + # a tab, space, or printable... + $$piece_ref .= substr($$line_ref, 0 ,1); + substr($$line_ref, 0, 1) = ''; + } else { + + # an undesirable character... + last; + } + } + return $ok; +} + +=head1 NAME + +Text::CSV - comma-separated values manipulation routines + +=head1 SYNOPSIS + + use Text::CSV; + + $version = Text::CSV->version(); # get the module version + + $csv = Text::CSV->new(); # create a new object + + $status = $csv->combine(@columns); # combine columns into a string + $line = $csv->string(); # get the combined string + + $status = $csv->parse($line); # parse a CSV string into fields + @columns = $csv->fields(); # get the parsed fields + + $status = $csv->status(); # get the most recent status + $bad_argument = $csv->error_input(); # get the most recent bad argument + +=head1 DESCRIPTION + +Text::CSV provides facilities for the composition and decomposition of +comma-separated values. An instance of the Text::CSV class can combine +fields into a CSV string and parse a CSV string into fields. + +=head1 FUNCTIONS + +=over 4 + +=item version + + $version = Text::CSV->version(); + +This function may be called as a class or an object method. It returns the current +module version. + +=item new + + $csv = Text::CSV->new(); + +This function may be called as a class or an object method. It returns a reference to a +newly created Text::CSV object. + +=item combine + + $status = $csv->combine(@columns); + +This object function constructs a CSV string from the arguments, returning +success or failure. Failure can result from lack of arguments or an argument +containing an invalid character. Upon success, C<string()> can be called to +retrieve the resultant CSV string. Upon failure, the value returned by +C<string()> is undefined and C<error_input()> can be called to retrieve an +invalid argument. + +=item string + + $line = $csv->string(); + +This object function returns the input to C<parse()> or the resultant CSV string of +C<combine()>, whichever was called more recently. + +=item parse + + $status = $csv->parse($line); + +This object function decomposes a CSV string into fields, returning +success or failure. Failure can result from a lack of argument or the given CSV +string is improperly formatted. Upon success, C<fields()> can be called to +retrieve the decomposed fields . Upon failure, the value returned by +C<fields()> is undefined and C<error_input()> can be called to retrieve the +invalid argument. + +=item fields + + @columns = $csv->fields(); + +This object function returns the input to C<combine()> or the resultant decomposed +fields of C<parse()>, whichever was called more recently. + +=item status + + $status = $csv->status(); + +This object function returns success (or failure) of C<combine()> or C<parse()>, +whichever was called more recently. + +=item error_input + + $bad_argument = $csv->error_input(); + +This object function returns the erroneous argument (if it exists) of C<combine()> +or C<parse()>, whichever was called more recently. + +=back + +=head1 EXAMPLE + + require Text::CSV; + + my $csv = Text::CSV->new; + + my $column = ''; + my $sample_input_string = '"I said, ""Hi!""",Yes,"",2.34,,"1.09"'; + if ($csv->parse($sample_input_string)) { + my @field = $csv->fields; + my $count = 0; + for $column (@field) { + print ++$count, " => ", $column, "\n"; + } + print "\n"; + } else { + my $err = $csv->error_input; + print "parse() failed on argument: ", $err, "\n"; + } + + my @sample_input_fields = ('You said, "Hello!"', + 5.67, + 'Surely', + '', + '3.14159'); + if ($csv->combine(@sample_input_fields)) { + my $string = $csv->string; + print $string, "\n"; + } else { + my $err = $csv->error_input; + print "combine() failed on argument: ", $err, "\n"; + } + +=head1 CAVEATS + +This module is based upon a working definition of CSV format which may not be +the most general. + +=over 4 + +=item 1 + +Allowable characters within a CSV field include 0x09 (tab) and the inclusive +range of 0x20 (space) through 0x7E (tilde). + +=item 2 + +A field within CSV may be surrounded by double-quotes. + +=item 3 + +A field within CSV must be surrounded by double-quotes to contain a comma. + +=item 4 + +A field within CSV must be surrounded by double-quotes to contain an embedded +double-quote, represented by a pair of consecutive double-quotes. + +=item 5 + +A CSV string may be terminated by 0x0A (line feed) or by 0x0D,0x0A +(carriage return, line feed). + +=head1 AUTHOR + +Alan Citterman F<E<lt>alan@mfgrtl.comE<gt>> + +=head1 SEE ALSO + +perl(1) + +=cut diff --git a/cpan/dist/Text-CSV/MANIFEST b/cpan/dist/Text-CSV/MANIFEST new file mode 100644 index 00000000..19df7eeb --- /dev/null +++ b/cpan/dist/Text-CSV/MANIFEST @@ -0,0 +1,5 @@ +README +MANIFEST +CSV.pm +Makefile.PL +test.pl diff --git a/cpan/dist/Text-CSV/Makefile.PL b/cpan/dist/Text-CSV/Makefile.PL new file mode 100644 index 00000000..c6bfa159 --- /dev/null +++ b/cpan/dist/Text-CSV/Makefile.PL @@ -0,0 +1,7 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'Text::CSV', + 'VERSION_FROM' => 'CSV.pm', # finds $VERSION +); diff --git a/cpan/dist/Text-CSV/README b/cpan/dist/Text-CSV/README new file mode 100644 index 00000000..e25e4cda --- /dev/null +++ b/cpan/dist/Text-CSV/README @@ -0,0 +1,32 @@ +Module: Text::CSV + +Description: + Text::CSV provides facilities for the composition and decomposition of + comma-separated values. An instance of the Text::CSV class can combine + fields into a CSV string and parse a CSV string into fields. + +Copying: + Copyright (c) 1997 Alan Citterman. All rights reserved. This program is + free software; you can redistribute it and/or modify it under the same + terms as Perl itself. + +Prerequisites: + perl 5.002 + +Build/Installation: + Standard build/installation supported by ExtUtils::MakeMaker(3)... + perl Makefile.PL + make + make test + make install + +Recent Changes: + Version 0.01 06/05/1997 + original version + +Planned Enhancements: + + extend constructor to accept parse() configuration to support other + variations of CSV + +Author: + Alan Citterman <alan@mfgrtl.com> diff --git a/cpan/dist/Text-CSV/test.pl b/cpan/dist/Text-CSV/test.pl new file mode 100644 index 00000000..f15dfd3b --- /dev/null +++ b/cpan/dist/Text-CSV/test.pl @@ -0,0 +1,131 @@ +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..20\n"; } +END {print "not ok 1\n" unless $loaded;} +use Text::CSV; +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +# +# empty subclass test +# +package Empty_Subclass; +@ISA = qw(Text::CSV); +package main; +my $empty = Empty_Subclass->new(); +if ($empty->version() and $empty->parse('') and $empty->combine('')) { + print "ok 2\n"; +} else { + print "not ok 2\n"; +} + +my $csv = Text::CSV->new(); + +if (! $csv->combine()) { # fail - missing argument + print "ok 3\n"; +} else { + print "not ok 3\n"; +} +if (! $csv->combine('abc', "def\n", 'ghi')) { # fail - bad character + print "ok 4\n"; +} else { + print "not ok 4\n"; +} +if ($csv->combine('') && ($csv->string eq q(""))) { # succeed + print "ok 5\n"; +} else { + print "not ok 5\n"; +} +if ($csv->combine('', '') && ($csv->string eq q("",""))) { # succeed + print "ok 6\n"; +} else { + print "not ok 6\n"; +} +if ($csv->combine('', 'I said, "Hi!"', '') && + ($csv->string eq q("","I said, ""Hi!""",""))) { # succeed + print "ok 7\n"; +} else { + print "not ok 7\n"; +} +if ($csv->combine('"', 'abc') && ($csv->string eq q("""","abc"))) { # succeed + print "ok 8\n"; +} else { + print "not ok 8\n"; +} +if ($csv->combine('abc', '"') && ($csv->string eq q("abc",""""))) { # succeed + print "ok 9\n"; +} else { + print "not ok 9\n"; +} +if ($csv->combine('abc', 'def', 'ghi') && + ($csv->string eq q("abc","def","ghi"))) { # succeed + print "ok 10\n"; +} else { + print "not ok 10\n"; +} +if ($csv->combine("abc\tdef", 'ghi') && + ($csv->string eq qq("abc\tdef","ghi"))) { # succeed + print "ok 11\n"; +} else { + print "not ok 11\n"; +} +if (! $csv->parse()) { # fail - missing argument + print "ok 12\n"; +} else { + print "not ok 12\n"; +} +if (! $csv->parse('"abc')) { # fail - missing closing double-quote + print "ok 13\n"; +} else { + print "not ok 13\n"; +} +if (! $csv->parse('ab"c')) { # fail - double-quote outside of double-quotes + print "ok 14\n"; +} else { + print "not ok 14\n"; +} +if (! $csv->parse('"ab"c"')) { # fail - bad character sequence + print "ok 15\n"; +} else { + print "not ok 15\n"; +} +if (! $csv->parse(qq("abc\nc"))) { # fail - bad character + print "ok 16\n"; +} else { + print "not ok 16\n"; +} +if (! $csv->status()) { # fail - test #16 should have failed + print "ok 17\n"; +} else { + print "not ok 17\n"; +} +if ($csv->parse(q(",")) and ($csv->fields())[0] eq ',') { # success + print "ok 18\n"; +} else { + print "not ok 18\n"; +} +if ($csv->parse(qq("","I said,\t""Hi!""","")) and +($csv->fields())[0] eq '' and +($csv->fields())[1] eq qq(I said,\t"Hi!") and +($csv->fields())[2] eq '') { # success + print "ok 19\n"; +} else { + print "not ok 19\n"; +} +if ($csv->status()) { # success - test #19 should have succeeded + print "ok 20\n"; +} else { + print "not ok 20\n"; +} diff --git a/cpan/lib/Text/CSV.pm b/cpan/lib/Text/CSV.pm new file mode 100644 index 00000000..bb03b2a0 --- /dev/null +++ b/cpan/lib/Text/CSV.pm @@ -0,0 +1,488 @@ +package Text::CSV; + +# Copyright (c) 1997 Alan Citterman. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +################################################################################ +# HISTORY +# +# Written by: +# Alan Citterman <alan@mfgrtl.com> +# +# Version 0.01 06/05/1997 +# original version +################################################################################ + +require 5.002; + +use strict; + +BEGIN { + use Exporter (); + use AutoLoader qw(AUTOLOAD); + use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + $VERSION = '0.01'; + @ISA = qw(Exporter AutoLoader); + @EXPORT = qw(); + @EXPORT_OK = qw(); + %EXPORT_TAGS = qw(); +} + +1; + +__END__ + +################################################################################ +# version +# +# class/object method expecting no arguments and returning the version number +# of Text::CSV. there are no side-effects. +################################################################################ +sub version { + return $VERSION; +} + +################################################################################ +# new +# +# class/object method expecting no arguments and returning a reference to a +# newly created Text::CSV object. +################################################################################ +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = {}; + $self->{'_STATUS'} = undef; + $self->{'_ERROR_INPUT'} = undef; + $self->{'_STRING'} = undef; + $self->{'_FIELDS'} = undef; + bless $self, $class; + return $self; +} + +################################################################################ +# status +# +# object method returning the success or failure of the most recent combine() +# or parse(). there are no side-effects. +################################################################################ +sub status { + my $self = shift; + return $self->{'_STATUS'}; +} + +################################################################################ +# error_input +# +# object method returning the first invalid argument to the most recent +# combine() or parse(). there are no side-effects. +################################################################################ +sub error_input { + my $self = shift; + return $self->{'_ERROR_INPUT'}; +} + +################################################################################ +# string +# +# object method returning the result of the most recent combine() or the +# input to the most recent parse(), whichever is more recent. there are no +# side-effects. +################################################################################ +sub string { + my $self = shift; + return $self->{'_STRING'}; +} + +################################################################################ +# fields +# +# object method returning the result of the most recent parse() or the input +# to the most recent combine(), whichever is more recent. there are no +# side-effects. +################################################################################ +sub fields { + my $self = shift; + if (ref($self->{'_FIELDS'})) { + return @{$self->{'_FIELDS'}}; + } + return undef; +} + +################################################################################ +# combine +# +# object method returning success or failure. the given arguments are +# combined into a single comma-separated value. failure can be the result of +# no arguments or an argument containing an invalid character. side-effects +# include: +# setting status() +# setting fields() +# setting string() +# setting error_input() +################################################################################ +sub combine { + my $self = shift; + my @part = @_; + $self->{'_FIELDS'} = \@part; + $self->{'_ERROR_INPUT'} = undef; + $self->{'_STATUS'} = 0; + $self->{'_STRING'} = ''; + my $column = ''; + my $combination = ''; + my $skip_comma = 1; + if ($#part >= 0) { + + # at least one argument was given for "combining"... + for $column (@part) { + if ($column =~ /[^\t\040-\176]/) { + + # an argument contained an invalid character... + $self->{'_ERROR_INPUT'} = $column; + return $self->{'_STATUS'}; + } + if ($skip_comma) { + + # do not put a comma before the first argument... + $skip_comma = 0; + } else { + + # do put a comma before all arguments except the first argument... + $combination .= ','; + } + $column =~ s/\042/\042\042/go; + $combination .= "\042"; + $combination .= $column; + $combination .= "\042"; + } + $self->{'_STRING'} = $combination; + $self->{'_STATUS'} = 1; + } + return $self->{'_STATUS'}; +} + +################################################################################ +# parse +# +# object method returning success or failure. the given argument is expected +# to be a valid comma-separated value. failure can be the result of +# no arguments or an argument containing an invalid sequence of characters. +# side-effects include: +# setting status() +# setting fields() +# setting string() +# setting error_input() +################################################################################ +sub parse { + my $self = shift; + $self->{'_STRING'} = shift; + $self->{'_FIELDS'} = undef; + $self->{'_ERROR_INPUT'} = $self->{'_STRING'}; + $self->{'_STATUS'} = 0; + if (!defined($self->{'_STRING'})) { + return $self->{'_STATUS'}; + } + my $keep_biting = 1; + my $palatable = 0; + my $line = $self->{'_STRING'}; + if ($line =~ /\n$/) { + chop($line); + if ($line =~ /\r$/) { + chop($line); + } + } + my $mouthful = ''; + my @part = (); + while ($keep_biting and ($palatable = $self->_bite(\$line, \$mouthful, \$keep_biting))) { + push(@part, $mouthful); + } + if ($palatable) { + $self->{'_ERROR_INPUT'} = undef; + $self->{'_FIELDS'} = \@part; + } + return $self->{'_STATUS'} = $palatable; +} + +################################################################################ +# _bite +# +# *private* class/object method returning success or failure. the arguments +# are: +# - a reference to a comma-separated value string +# - a reference to a return string +# - a reference to a return boolean +# upon success the first comma-separated value of the csv string is +# transferred to the return string and the boolean is set to true if a comma +# followed that value. in other words, "bite" one value off of csv +# returning the remaining string, the "piece" bitten, and if there's any +# more. failure can be the result of the csv string containing an invalid +# sequence of characters. +# +# from the csv string and +# to be a valid comma-separated value. failure can be the result of +# no arguments or an argument containing an invalid sequence of characters. +# side-effects include: +# setting status() +# setting fields() +# setting string() +# setting error_input() +################################################################################ +sub _bite { + my ($self, $line_ref, $piece_ref, $bite_again_ref) = @_; + my $in_quotes = 0; + my $ok = 0; + $$piece_ref = ''; + $$bite_again_ref = 0; + while (1) { + if (length($$line_ref) < 1) { + + # end of string... + if ($in_quotes) { + + # end of string, missing closing double-quote... + last; + } else { + + # proper end of string... + $ok = 1; + last; + } + } elsif ($$line_ref =~ /^\042/) { + + # double-quote... + if ($in_quotes) { + if (length($$line_ref) == 1) { + + # closing double-quote at end of string... + substr($$line_ref, 0, 1) = ''; + $ok = 1; + last; + } elsif ($$line_ref =~ /^\042\042/) { + + # an embedded double-quote... + $$piece_ref .= "\042"; + substr($$line_ref, 0, 2) = ''; + } elsif ($$line_ref =~ /^\042,/) { + + # closing double-quote followed by a comma... + substr($$line_ref, 0, 2) = ''; + $$bite_again_ref = 1; + $ok = 1; + last; + } else { + + # double-quote, followed by undesirable character (bad character sequence)... + last; + } + } else { + if (length($$piece_ref) < 1) { + + # starting double-quote at beginning of string + $in_quotes = 1; + substr($$line_ref, 0, 1) = ''; + } else { + + # double-quote, outside of double-quotes (bad character sequence)... + last; + } + } + } elsif ($$line_ref =~ /^,/) { + + # comma... + if ($in_quotes) { + + # a comma, inside double-quotes... + $$piece_ref .= substr($$line_ref, 0 ,1); + substr($$line_ref, 0, 1) = ''; + } else { + + # a comma, which separates values... + substr($$line_ref, 0, 1) = ''; + $$bite_again_ref = 1; + $ok = 1; + last; + } + } elsif ($$line_ref =~ /^[\t\040-\176]/) { + + # a tab, space, or printable... + $$piece_ref .= substr($$line_ref, 0 ,1); + substr($$line_ref, 0, 1) = ''; + } else { + + # an undesirable character... + last; + } + } + return $ok; +} + +=head1 NAME + +Text::CSV - comma-separated values manipulation routines + +=head1 SYNOPSIS + + use Text::CSV; + + $version = Text::CSV->version(); # get the module version + + $csv = Text::CSV->new(); # create a new object + + $status = $csv->combine(@columns); # combine columns into a string + $line = $csv->string(); # get the combined string + + $status = $csv->parse($line); # parse a CSV string into fields + @columns = $csv->fields(); # get the parsed fields + + $status = $csv->status(); # get the most recent status + $bad_argument = $csv->error_input(); # get the most recent bad argument + +=head1 DESCRIPTION + +Text::CSV provides facilities for the composition and decomposition of +comma-separated values. An instance of the Text::CSV class can combine +fields into a CSV string and parse a CSV string into fields. + +=head1 FUNCTIONS + +=over 4 + +=item version + + $version = Text::CSV->version(); + +This function may be called as a class or an object method. It returns the current +module version. + +=item new + + $csv = Text::CSV->new(); + +This function may be called as a class or an object method. It returns a reference to a +newly created Text::CSV object. + +=item combine + + $status = $csv->combine(@columns); + +This object function constructs a CSV string from the arguments, returning +success or failure. Failure can result from lack of arguments or an argument +containing an invalid character. Upon success, C<string()> can be called to +retrieve the resultant CSV string. Upon failure, the value returned by +C<string()> is undefined and C<error_input()> can be called to retrieve an +invalid argument. + +=item string + + $line = $csv->string(); + +This object function returns the input to C<parse()> or the resultant CSV string of +C<combine()>, whichever was called more recently. + +=item parse + + $status = $csv->parse($line); + +This object function decomposes a CSV string into fields, returning +success or failure. Failure can result from a lack of argument or the given CSV +string is improperly formatted. Upon success, C<fields()> can be called to +retrieve the decomposed fields . Upon failure, the value returned by +C<fields()> is undefined and C<error_input()> can be called to retrieve the +invalid argument. + +=item fields + + @columns = $csv->fields(); + +This object function returns the input to C<combine()> or the resultant decomposed +fields of C<parse()>, whichever was called more recently. + +=item status + + $status = $csv->status(); + +This object function returns success (or failure) of C<combine()> or C<parse()>, +whichever was called more recently. + +=item error_input + + $bad_argument = $csv->error_input(); + +This object function returns the erroneous argument (if it exists) of C<combine()> +or C<parse()>, whichever was called more recently. + +=back + +=head1 EXAMPLE + + require Text::CSV; + + my $csv = Text::CSV->new; + + my $column = ''; + my $sample_input_string = '"I said, ""Hi!""",Yes,"",2.34,,"1.09"'; + if ($csv->parse($sample_input_string)) { + my @field = $csv->fields; + my $count = 0; + for $column (@field) { + print ++$count, " => ", $column, "\n"; + } + print "\n"; + } else { + my $err = $csv->error_input; + print "parse() failed on argument: ", $err, "\n"; + } + + my @sample_input_fields = ('You said, "Hello!"', + 5.67, + 'Surely', + '', + '3.14159'); + if ($csv->combine(@sample_input_fields)) { + my $string = $csv->string; + print $string, "\n"; + } else { + my $err = $csv->error_input; + print "combine() failed on argument: ", $err, "\n"; + } + +=head1 CAVEATS + +This module is based upon a working definition of CSV format which may not be +the most general. + +=over 4 + +=item 1 + +Allowable characters within a CSV field include 0x09 (tab) and the inclusive +range of 0x20 (space) through 0x7E (tilde). + +=item 2 + +A field within CSV may be surrounded by double-quotes. + +=item 3 + +A field within CSV must be surrounded by double-quotes to contain a comma. + +=item 4 + +A field within CSV must be surrounded by double-quotes to contain an embedded +double-quote, represented by a pair of consecutive double-quotes. + +=item 5 + +A CSV string may be terminated by 0x0A (line feed) or by 0x0D,0x0A +(carriage return, line feed). + +=head1 AUTHOR + +Alan Citterman F<E<lt>alan@mfgrtl.comE<gt>> + +=head1 SEE ALSO + +perl(1) + +=cut |
