Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package perl-Text-CSV_XS for openSUSE:Factory checked in at 2023-08-09 17:24:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-Text-CSV_XS (Old) and /work/SRC/openSUSE:Factory/.perl-Text-CSV_XS.new.11712 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "perl-Text-CSV_XS" Wed Aug 9 17:24:28 2023 rev:50 rq:1102958 version:1.510.0 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-Text-CSV_XS/perl-Text-CSV_XS.changes 2023-03-11 18:24:22.306984348 +0100 +++ /work/SRC/openSUSE:Factory/.perl-Text-CSV_XS.new.11712/perl-Text-CSV_XS.changes 2023-08-09 17:24:32.549114756 +0200 @@ -1,0 +2,15 @@ +Tue Aug 8 03:10:51 UTC 2023 - Tina Müller <timueller+p...@suse.de> + +- updated to 1.51 + see /usr/share/doc/packages/perl-Text-CSV_XS/ChangeLog + + 1.51 - 2023-08-07, H.Merijn Brand + * Contact e-mail update + * Attribute skip_empty_rows extended + * Fix comments (PR#45) + * Fix help (x12340, PR#46) + * Update to Devel::PPPort-3.71 + * Fix HTML on Windows + * Fix double header-interpretation on bom + headers => "auto" (issue 47) + +------------------------------------------------------------------- Old: ---- Text-CSV_XS-1.50.tgz New: ---- Text-CSV_XS-1.51.tgz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-Text-CSV_XS.spec ++++++ --- /var/tmp/diff_new_pack.9BRxaQ/_old 2023-08-09 17:24:33.117118292 +0200 +++ /var/tmp/diff_new_pack.9BRxaQ/_new 2023-08-09 17:24:33.121118317 +0200 @@ -18,15 +18,18 @@ %define cpan_name Text-CSV_XS Name: perl-Text-CSV_XS -Version: 1.50 +Version: 1.510.0 Release: 0 +%define cpan_version 1.51 License: Artistic-1.0 OR GPL-1.0-or-later Summary: Comma-Separated Values manipulation routines URL: https://metacpan.org/release/%{cpan_name} -Source0: https://cpan.metacpan.org/authors/id/H/HM/HMBRAND/%{cpan_name}-%{version}.tgz +Source0: https://cpan.metacpan.org/authors/id/H/HM/HMBRAND/%{cpan_name}-%{cpan_version}.tgz Source1: cpanspec.yml BuildRequires: perl BuildRequires: perl-macros +Provides: perl(Text::CSV_XS) = 1.510.0 +%define __perllib_provides /bin/true Recommends: perl(Encode) >= 3.19 %{perl_requires} @@ -39,9 +42,9 @@ user-specified characters for delimiters, separators, and escapes. %prep -%autosetup -n %{cpan_name}-%{version} +%autosetup -n %{cpan_name}-%{cpan_version} -find . -type f ! -path "*/t/*" ! -name "*.pl" ! -path "*/bin/*" ! -path "*/script/*" ! -name "configure" -print0 | xargs -0 chmod 644 +find . -type f ! -path "*/t/*" ! -name "*.pl" ! -path "*/bin/*" ! -path "*/script/*" ! -path "*/scripts/*" ! -name "configure" -print0 | xargs -0 chmod 644 # MANUAL BEGIN sed -i -e 's,/pro/bin/perl,/usr/bin/perl,' examples/* # MANUAL END ++++++ Text-CSV_XS-1.50.tgz -> Text-CSV_XS-1.51.tgz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/CSV_XS.pm new/Text-CSV_XS-1.51/CSV_XS.pm --- old/Text-CSV_XS-1.50/CSV_XS.pm 2023-03-01 09:35:05.000000000 +0100 +++ new/Text-CSV_XS-1.51/CSV_XS.pm 2023-08-07 13:57:49.000000000 +0200 @@ -9,12 +9,9 @@ # HISTORY # -# 0.24 - -# H.Merijn Brand (h.m.br...@xs4all.nl) -# 0.10 - 0.23 -# Jochen Wiedmann <j...@ispsoft.de> -# Based on (the original) Text::CSV by: -# Alan Citterman <a...@mfgrtl.com> +# 0.24 - H.Merijn Brand <pe...@tux.freedom.nl> +# 0.10 - 0.23 Jochen Wiedmann <j...@ispsoft.de> +# Based on (the original) Text::CSV by Alan Citterman <a...@mfgrtl.com> require 5.006001; @@ -26,7 +23,7 @@ use Carp; use vars qw( $VERSION @ISA @EXPORT_OK %EXPORT_TAGS ); -$VERSION = "1.50"; +$VERSION = "1.51"; @ISA = qw( Exporter ); XSLoader::load ("Text::CSV_XS", $VERSION); @@ -51,7 +48,7 @@ CSV_TYPE_NV )], ); -@EXPORT_OK = (qw( csv PV IV NV ), @{$EXPORT_TAGS{CONSTANTS}}); +@EXPORT_OK = (qw( csv PV IV NV ), @{$EXPORT_TAGS{'CONSTANTS'}}); if ($] < 5.008002) { no warnings "redefine"; @@ -113,6 +110,7 @@ '_BOUND_COLUMNS' => undef, '_AHEAD' => undef, '_FORMULA_CB' => undef, + '_EMPTROW_CB' => undef, 'ENCODING' => undef, ); @@ -255,8 +253,9 @@ $last_new_err = Text::CSV_XS->SetDiag (0); defined $\ && !exists $attr{'eol'} and $self->{'eol'} = $\; bless $self, $class; - defined $self->{'types'} and $self->types ($self->{'types'}); - defined $attr_formula and $self->{'formula'} = _supported_formula ($self, $attr_formula); + defined $self->{'types'} and $self->types ($self->{'types'}); + defined $self->{'skip_empty_rows'} and $self->{'skip_empty_rows'} = _supported_skip_empty_rows ($self, $self->{'skip_empty_rows'}); + defined $attr_formula and $self->{'formula'} = _supported_formula ($self, $attr_formula); $self; } # new @@ -455,13 +454,36 @@ my $self = shift; @_ and $self->_set_attr_X ("strict", shift); $self->{'strict'}; - } # always_quote + } # strict + +sub _supported_skip_empty_rows { + my ($self, $f) = @_; + defined $f or return 0; + if ($self && $f && ref $f && ref $f eq "CODE") { + $self->{'_EMPTROW_CB'} = $f; + return 6; + } + $f =~ m/^(?: 0 | undef )$/xi ? 0 : + $f =~ m/^(?: 1 | skip )$/xi ? 1 : + $f =~ m/^(?: 2 | eof | stop )$/xi ? 2 : + $f =~ m/^(?: 3 | die )$/xi ? 3 : + $f =~ m/^(?: 4 | croak )$/xi ? 4 : + $f =~ m/^(?: 5 | error )$/xi ? 5 : + $f =~ m/^(?: 6 | cb )$/xi ? 6 : do { + $self ||= "Text::CSV_XS"; + croak ($self->_SetDiagInfo (1500, "skip_empty_rows '$f' is not supported")); + }; + } # _supported_skip_empty_rows sub skip_empty_rows { my $self = shift; - @_ and $self->_set_attr_X ("skip_empty_rows", shift); - $self->{'skip_empty_rows'}; - } # always_quote + @_ and $self->_set_attr_N ("skip_empty_rows", _supported_skip_empty_rows ($self, shift)); + my $ser = $self->{'skip_empty_rows'}; + $ser == 6 or $self->{'_EMPTROW_CB'} = undef; + $ser <= 1 ? $ser : $ser == 2 ? "eof" : $ser == 3 ? "die" : + $ser == 4 ? "croak" : $ser == 5 ? "error" : + $self->{'_EMPTROW_CB'}; + } # skip_empty_rows sub _SetDiagInfo { my ($self, $err, $msg) = @_; @@ -496,7 +518,8 @@ @_ and $self->_set_attr_N ("formula", _supported_formula ($self, shift)); $self->{'formula'} == 6 or $self->{'_FORMULA_CB'} = undef; [qw( none die croak diag empty undef cb )]->[_supported_formula ($self, $self->{'formula'})]; - } # always_quote + } # formula + sub formula_handling { my $self = shift; $self->formula (@_); @@ -621,7 +644,7 @@ sub eof { my $self = shift; return $self->{'_EOF'}; - } # status + } # eof sub types { my $self = shift; @@ -996,7 +1019,7 @@ ref $args{'munge_column_names'} eq "HASH" and @hdr = map { $args{'munge_column_names'}->{$_} || $_ } @hdr; my %hdr; $hdr{$_}++ for @hdr; - exists $hdr{""} and croak ($self->SetDiag (1012)); + exists $hdr{''} and croak ($self->SetDiag (1012)); unless (keys %hdr == @hdr) { croak ($self->_SetDiagInfo (1013, join ", " => map { "$_ ($hdr{$_})" } grep { $hdr{$_} > 1 } keys %hdr)); @@ -1390,7 +1413,7 @@ !defined $c->{'hd_s'} && $c->{'attr'}{'sep'} and $c->{'hd_s'} = [ $c->{'attr'}{'sep'} ]; defined $c->{'hd_s'} and $harg{'sep_set'} = $c->{'hd_s'}; - defined $c->{'hd_d'} and $harg{'detect_bom'} = $c->{'hd_b'}; + defined $c->{'hd_b'} and $harg{'detect_bom'} = $c->{'hd_b'}; defined $c->{'hd_m'} and $harg{'munge_column_names'} = $hdrs ? "none" : $c->{'hd_m'}; defined $c->{'hd_c'} and $harg{'set_column_names'} = $hdrs ? 0 : $c->{'hd_c'}; @row1 = $csv->header ($fh, \%harg); @@ -1417,28 +1440,33 @@ $c->{'fltr'} && grep m/\D/ => keys %{$c->{'fltr'}} and $hdrs ||= "auto"; if (defined $hdrs) { - if (!ref $hdrs) { - if ($hdrs eq "skip") { - $csv->getline ($fh); # discard; + if (!ref $hdrs or ref $hdrs eq "CODE") { + my $h = $c->{'hd_b'} + ? [ $csv->column_names () ] + : $csv->getline ($fh); + my $has_h = $h && @$h; + + if (ref $hdrs) { + $has_h or return; + my $cr = $hdrs; + $hdrs = [ map { $cr->($hdr{$_} || $_) } @{$h} ]; + } + elsif ($hdrs eq "skip") { + # discard; } elsif ($hdrs eq "auto") { - my $h = $csv->getline ($fh) or return; + $has_h or return; $hdrs = [ map { $hdr{$_} || $_ } @{$h} ]; } elsif ($hdrs eq "lc") { - my $h = $csv->getline ($fh) or return; + $has_h or return; $hdrs = [ map { lc ($hdr{$_} || $_) } @{$h} ]; } elsif ($hdrs eq "uc") { - my $h = $csv->getline ($fh) or return; + $has_h or return; $hdrs = [ map { uc ($hdr{$_} || $_) } @{$h} ]; } } - elsif (ref $hdrs eq "CODE") { - my $h = $csv->getline ($fh) or return; - my $cr = $hdrs; - $hdrs = [ map { $cr->($hdr{$_} || $_) } @{$h} ]; - } $c->{'kh'} and $hdrs and @{$c->{'kh'}} = @{$hdrs}; } @@ -1470,7 +1498,7 @@ do { my @h = $csv->column_names ($hdrs); my %h; $h{$_}++ for @h; - exists $h{""} and croak ($csv->SetDiag (1012)); + exists $h{''} and croak ($csv->SetDiag (1012)); unless (keys %h == @h) { croak ($csv->_SetDiagInfo (1013, join ", " => map { "$_ ($h{$_})" } grep { $h{$_} > 1 } keys %h)); @@ -1570,7 +1598,7 @@ headers => "auto"); # as array of hash # Write array of arrays as csv file - csv (in => $aoa, out => "file.csv", sep_char=> ";"); + csv (in => $aoa, out => "file.csv", sep_char => ";"); # Only show lines where "code" is odd csv (in => "data.csv", filter => { code => sub { $_ % 2 }}); @@ -1956,14 +1984,82 @@ X<skip_empty_rows> my $csv = Text::CSV_XS->new ({ skip_empty_rows => 1 }); - $csv->skip_empty_rows (0); + $csv->skip_empty_rows ("eof"); my $f = $csv->skip_empty_rows; -If this attribute is set to C<1>, any row that has an L</eol> immediately -following the start of line will be skipped. Default behavior is to return -one single empty field. +This attribute defines the behavior for empty rows: an L</eol> immediately +following the start of line. Default behavior is to return one single empty +field. + +This attribute is only used in parsing. This attribute is ineffective when +using L</parse> and L</fields>. + +Possible values for this attribute are + +=over 2 + +=item 0 | undef + + my $csv = Text::CSV_XS->new ({ skip_empty_rows => 0 }); + $csv->skip_empty_rows (undef); + +No special action is taken. The result will be one single empty field. + +=item 1 | "skip" + + my $csv = Text::CSV_XS->new ({ skip_empty_rows => 1 }); + $csv->skip_empty_rows ("skip"); + +The row will be skipped. -This attribute is only used in parsing. +=item 2 | "eof" | "stop" + + my $csv = Text::CSV_XS->new ({ skip_empty_rows => 2 }); + $csv->skip_empty_rows ("eof"); + +The parsing will stop as if an L</eof> was detected. + +=item 3 | "die" + + my $csv = Text::CSV_XS->new ({ skip_empty_rows => 3 }); + $csv->skip_empty_rows ("die"); + +The parsing will stop. The internal error code will be set to 2015 and the +parser will C<die>. + +=item 4 | "croak" + + my $csv = Text::CSV_XS->new ({ skip_empty_rows => 4 }); + $csv->skip_empty_rows ("croak"); + +The parsing will stop. The internal error code will be set to 2015 and the +parser will C<croak>. + +=item 5 | "error" + + my $csv = Text::CSV_XS->new ({ skip_empty_rows => 5 }); + $csv->skip_empty_rows ("error"); + +The parsing will fail. The internal error code will be set to 2015. + +=item callback + + my $csv = Text::CSV_XS->new ({ skip_empty_rows => sub { [] } }); + $csv->skip_empty_rows (sub { [ 42, $., undef, "empty" ] }); + +The callback is invoked and its result used instead. If you want the parse +to stop after the callback, make sure to return a false value. + +The returned value from the callback should be an array-ref. Any other type +will cause the parse to stop, so these are equivalent in behavior: + + csv (in => $fh, skip_empty_rows => "stop"); + csv (in => $fh. skip_empty_rows => sub { 0; }); + +=back + +Without arguments, the current value is returned: C<0>, C<1>, C<eof>, C<die>, +C<croak> or the callback. =head3 formula_handling X<formula_handling> @@ -3563,6 +3659,8 @@ my $aoa = csv (in => $fh, headers => "skip"); +C<skip> is invalid/ignored in combinations with L<C<detect_bom>|/detect_bom>. + =item auto X<auto> @@ -4606,6 +4704,18 @@ will not return flags either. L</fragment> can reduce the required rows I<or> columns, but cannot combine them. +=item provider + + csv (in => $fh) vs csv (provider => sub { get_line }); + +Whatever the attribute name might end up to be, this should make it easier +to add input providers for parsing. Currently most special variations for +the C<in> attribute are aimed at CSV generation: e.g. a callback is defined +to return a reference to a record. This new attribute should enable passing +data to parse, like getline. + +Suggested by Johan Vromans. + =item Cookbook Write a document that has recipes for most known non-standard (and maybe @@ -4881,6 +4991,12 @@ Inconsistent number of fields under strict parsing. =item * +2015 "ERW - Empty row" +X<2015> + +An empty row was not allowed. + +=item * 2021 "EIQ - NL char inside quotes, binary off" X<2021> @@ -5033,7 +5149,7 @@ escape and separator characters, the binary mode and the print and getline methods. See F<ChangeLog> releases 0.10 through 0.23. -H.Merijn Brand F<E<lt>h.m.br...@xs4all.nle<gt>> cleaned up the code, added +H.Merijn Brand F<E<lt>hmbr...@cpan.orge<gt>> cleaned up the code, added the field flags methods, wrote the major part of the test suite, completed the documentation, fixed most RT bugs, added all the allow flags and the L</csv> function. See ChangeLog releases 0.25 and on. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/CSV_XS.xs new/Text-CSV_XS-1.51/CSV_XS.xs --- old/Text-CSV_XS-1.50/CSV_XS.xs 2023-03-01 09:17:51.000000000 +0100 +++ new/Text-CSV_XS-1.51/CSV_XS.xs 2023-08-07 09:06:27.000000000 +0200 @@ -276,6 +276,7 @@ { 2012, "EOF - End of data in parsing input stream" }, { 2013, "ESP - Specification error for fragments RFC7111" }, { 2014, "ENF - Inconsistent number of fields" }, + { 2015, "ERW - Empty row" }, /* EIQ - Error Inside Quotes */ { 2021, "EIQ - NL char inside quotes, binary off" }, @@ -735,7 +736,6 @@ csv->decode_utf8 = bool_opt ("decode_utf8"); csv->always_quote = bool_opt ("always_quote"); csv->strict = bool_opt ("strict"); - csv->skip_empty_rows = bool_opt ("skip_empty_rows"); csv->quote_empty = bool_opt ("quote_empty"); csv->quote_space = bool_opt_def ("quote_space", 1); csv->escape_null = bool_opt_def ("escape_null", 1); @@ -751,6 +751,7 @@ csv->auto_diag = num_opt ("auto_diag"); csv->diag_verbose = num_opt ("diag_verbose"); csv->keep_meta_info = num_opt ("keep_meta_info"); + csv->skip_empty_rows = num_opt ("skip_empty_rows"); csv->formula = num_opt ("formula"); unless (csv->escape_char) csv->escape_null = 0; @@ -951,6 +952,79 @@ return NULL; } /* _formula */ +#define SkipEmptyRow {\ + int ser = csv->skip_empty_rows; \ + \ + if (ser == 3) { (void)SetDiag (csv, 2015); die ("Empty row"); } \ + if (ser == 4) { (void)SetDiag (csv, 2015); croak ("Empty row"); } \ + if (ser == 5) { (void)SetDiag (csv, 2015); return FALSE; } \ + \ + if (ser <= 2) { /* skip & eof */ \ + csv->fld_idx = 0; \ + c = CSV_GET; \ + if (c == EOF || ser == 2) { \ + sv_free (sv); \ + sv = NULL; \ + waitingForField = 0; \ + if (ser == 2) return FALSE; \ + break; \ + } \ + } \ + \ + if (ser == 6) { \ + int result, n, i; \ + SV *rv, **svp = hv_fetchs (csv->self, "_EMPTROW_CB", FALSE); \ + AV *avp; \ + unless (svp && _is_coderef (*svp)) \ + return FALSE; /* A callback is wanted, but none found */ \ + \ + dSP; \ + ENTER; \ + SAVE_DEFSV; /* local $_ */ \ + DEFSV = sv; \ + PUSHMARK (SP); \ + PUTBACK; \ + result = call_sv (*svp, G_SCALAR); \ + SPAGAIN; \ + unless (result) { \ + /* A false return will stop the parsing */ \ + sv_free (sv); \ + sv = NULL; \ + waitingForField = 0; \ + return FALSE; \ + } \ + \ + PUTBACK; \ + LEAVE; \ + \ + rv = POPs; \ + /* Result should be a ref to a list. */ \ + unless (_is_arrayref (rv)) \ + return FALSE; \ + \ + avp = (AV *)SvRV (rv); \ + \ + unless (avp) return FALSE; \ + n = av_len (avp); \ + if (n <= 0) return TRUE; \ + \ + if (csv->is_bound && csv->is_bound < n) \ + n = csv->is_bound - 1; \ + \ + for (i = 0; i <= n; i++) { \ + SV **svp = av_fetch (avp, i, FALSE); \ + sv = svp && *svp ? *svp : NULL; \ + if (sv) { \ + SvREFCNT_inc (sv); \ + /* upgrade IV to IVPV if needed */ \ + (void)SvPV_nolen (sv); \ + } \ + AV_PUSH; \ + } \ + return TRUE; \ + } \ + } + #define Combine(csv,dst,fields) cx_Combine (aTHX_ csv, dst, fields) static int cx_Combine (pTHX_ csv_t *csv, SV *dst, AV *fields) { SSize_t i, n; @@ -958,7 +1032,7 @@ int aq = (int)csv->always_quote; int qe = (int)csv->quote_empty; int kmi = (int)csv->keep_meta_info; - AV *qm = NULL; + AV *qm = NULL; n = (IV)av_len (fields); if (n < 0 && csv->is_bound) { @@ -1288,11 +1362,13 @@ #endif #define AV_PUSH { \ + int svc; \ *SvEND (sv) = (char)0; \ + svc = SvCUR (sv); \ SvUTF8_off (sv); \ - if (csv->formula && SvCUR (sv) && *(SvPV_nolen (sv)) == '=') \ + if (svc && csv->formula && *(SvPV_nolen (sv)) == '=') \ (void)_formula (csv, sv, NULL, fnum); \ - if (SvCUR (sv) == 0 && ( \ + if (svc == 0 && ( \ csv->empty_is_undef || \ (!(f & CSV_FLAGS_QUO) && csv->blank_is_undef))) \ SvSetUndef (sv); \ @@ -1679,14 +1755,7 @@ _pretty_strl (csv->bptr + csv->used)); #endif if (fnum == 1 && f == 0 && SvCUR (sv) == 0 && csv->skip_empty_rows) { - csv->fld_idx = 0; - c = CSV_GET; - if (c == EOF) { - sv_free (sv); - sv = NULL; - waitingForField = 0; - break; - } + SkipEmptyRow; goto restart; } @@ -1814,14 +1883,7 @@ csv->used--; csv->has_ahead++; if (fnum == 1 && f == 0 && SvCUR (sv) == 0 && csv->skip_empty_rows) { - csv->fld_idx = 0; - c = CSV_GET; - if (c == EOF) { - sv_free (sv); - sv = NULL; - waitingForField = 0; - break; - } + SkipEmptyRow; goto restart; } AV_PUSH; @@ -1879,14 +1941,7 @@ csv->used--; csv->has_ahead++; if (fnum == 1 && f == 0 && SvCUR (sv) == 0 && csv->skip_empty_rows) { - csv->fld_idx = 0; - c = CSV_GET; - if (c == EOF) { - sv_free (sv); - sv = NULL; - waitingForField = 0; - break; - } + SkipEmptyRow; goto restart; } AV_PUSH; @@ -2008,8 +2063,11 @@ if (f & CSV_FLAGS_QUO) ERROR_INSIDE_QUOTES (2027); - if (sv) + if (sv) { AV_PUSH; + } + else if (f == 0 && fnum == 1 && csv->skip_empty_rows == 1) + return FALSE; return TRUE; } /* Parse */ @@ -2276,9 +2334,7 @@ Perl_load_module (aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvs ("IO::Handle"), NULL, NULL, NULL); void -SetDiag (self, xse, ...) - SV *self - int xse +SetDiag (SV *self, int xse, ...) PPCODE: HV *hv; @@ -2303,8 +2359,7 @@ /* XS SetDiag */ void -error_input (self) - SV *self +error_input (SV *self) PPCODE: if (self && SvOK (self) && SvROK (self) && SvTYPE (SvRV (self)) == SVt_PVHV) { @@ -2322,11 +2377,7 @@ /* XS error_input */ void -Combine (self, dst, fields, useIO) - SV *self - SV *dst - SV *fields - bool useIO +Combine (SV *self, SV *dst, SV *fields, bool useIO) PPCODE: HV *hv; @@ -2339,11 +2390,7 @@ /* XS Combine */ void -Parse (self, src, fields, fflags) - SV *self - SV *src - SV *fields - SV *fflags +Parse (SV *self, SV *src, SV *fields, SV *fflags) PPCODE: HV *hv; @@ -2359,10 +2406,7 @@ /* XS Parse */ void -print (self, io, fields) - SV *self - SV *io - SV *fields +print (SV *self, SV *io, SV *fields) PPCODE: HV *hv; @@ -2383,9 +2427,7 @@ /* XS print */ void -getline (self, io) - SV *self - SV *io +getline (SV *self, SV *io) PPCODE: HV *hv; @@ -2402,9 +2444,7 @@ /* XS getline */ void -getline_all (self, io, ...) - SV *self - SV *io +getline_all (SV *self, SV *io, ...) PPCODE: HV *hv; @@ -2420,10 +2460,7 @@ /* XS getline_all */ void -_cache_set (self, idx, val) - SV *self - int idx - SV *val +_cache_set (SV *self, int idx, SV *val) PPCODE: HV *hv; @@ -2434,8 +2471,7 @@ /* XS _cache_set */ void -_cache_diag (self) - SV *self +_cache_diag (SV *self) PPCODE: HV *hv; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/ChangeLog new/Text-CSV_XS-1.51/ChangeLog --- old/Text-CSV_XS-1.50/ChangeLog 2023-03-01 09:55:17.000000000 +0100 +++ new/Text-CSV_XS-1.51/ChangeLog 2023-08-07 13:58:29.000000000 +0200 @@ -1,3 +1,12 @@ +1.51 - 2023-08-07, H.Merijn Brand + * Contact e-mail update + * Attribute skip_empty_rows extended + * Fix comments (PR#45) + * Fix help (x12340, PR#46) + * Update to Devel::PPPort-3.71 + * Fix HTML on Windows + * Fix double header-interpretation on bom + headers => "auto" (issue 47) + 1.50 - 2023-03-01, H.Merijn Brand * Promote sep to sep_set in csv () with auto-headers * Fix bug in set_diag surfaced by PERL_RC_STACK diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/MANIFEST new/Text-CSV_XS-1.51/MANIFEST --- old/Text-CSV_XS-1.50/MANIFEST 2023-03-01 11:54:03.000000000 +0100 +++ new/Text-CSV_XS-1.51/MANIFEST 2023-08-07 18:20:02.000000000 +0200 @@ -26,6 +26,8 @@ t/60_samples.t Miscellaneous problems from the modules history. t/65_allow.t Allow bad formats t/66_formula.t Formula behavior +t/67_emptrow.t Empty row behavior +t/68_header.t Test header option combinations t/70_rt.t Tests based on RT reports t/75_hashref.t getline_hr related tests t/76_magic.t array_ref from magic diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/META.json new/Text-CSV_XS-1.51/META.json --- old/Text-CSV_XS-1.50/META.json 2023-03-01 11:54:04.000000000 +0100 +++ new/Text-CSV_XS-1.51/META.json 2023-08-07 18:20:03.000000000 +0200 @@ -1,67 +1,70 @@ { - "meta-spec" : { - "version" : 2, - "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec" + "release_status" : "stable", + "abstract" : "Comma-Separated Values manipulation routines", + "resources" : { + "bugtracker" : { + "web" : "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Text-CSV_XS" }, - "author" : [ - "H.Merijn Brand <h.m.br...@xs4all.nl>" + "license" : [ + "http://dev.perl.org/licenses/" ], + "x_IRC" : "irc://irc.perl.org/#csv", + "homepage" : "https://metacpan.org/pod/Text::CSV_XS", + "repository" : { + "web" : "https://github.com/Tux/Text-CSV_XS", + "url" : "https://github.com/Tux/Text-CSV_XS", + "type" : "git" + } + }, "generated_by" : "Author", - "license" : [ - "perl_5" - ], + "provides" : { + "Text::CSV_XS" : { + "file" : "CSV_XS.pm", + "version" : "1.51" + } + }, "prereqs" : { + "test" : { + "requires" : { + "Test::More" : "0", + "Tie::Scalar" : "0" + } + }, "build" : { "requires" : { "Config" : "0" - } - }, - "test" : { - "requires" : { - "Tie::Scalar" : "0", - "Test::More" : "0" - } - }, + } + }, "runtime" : { "recommends" : { "Encode" : "3.19" - }, + }, "requires" : { "perl" : "5.006001", "XSLoader" : "0", "IO::Handle" : "0" - } - }, + } + }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" - } - } - }, - "version" : "1.50", - "provides" : { - "Text::CSV_XS" : { - "file" : "CSV_XS.pm", - "version" : "1.50" - } - }, - "name" : "Text-CSV_XS", - "release_status" : "stable", - "resources" : { - "license" : [ - "http://dev.perl.org/licenses/" - ], - "homepage" : "https://metacpan.org/pod/Text::CSV_XS", - "repository" : { - "url" : "https://github.com/Tux/Text-CSV_XS", - "web" : "https://github.com/Tux/Text-CSV_XS", - "type" : "git" }, - "x_IRC" : "irc://irc.perl.org/#csv", - "bugtracker" : { - "web" : "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Text-CSV_XS" + "recommends" : { + "ExtUtils::MakeMaker" : "7.70" } - }, - "dynamic_config" : 1, - "abstract" : "Comma-Separated Values manipulation routines" - } + } + }, + "license" : [ + "perl_5" + ], + "version" : "1.51", + "author" : [ + "H.Merijn Brand <hmbrand.org>" + ], + "name" : "Text-CSV_XS", + "meta-spec" : { + "version" : 2, + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec" + }, + "dynamic_config" : 1 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/META.yml new/Text-CSV_XS-1.51/META.yml --- old/Text-CSV_XS-1.50/META.yml 2023-03-01 11:54:04.000000000 +0100 +++ new/Text-CSV_XS-1.51/META.yml 2023-08-07 18:20:03.000000000 +0200 @@ -1,7 +1,7 @@ --- abstract: Comma-Separated Values manipulation routines author: - - H.Merijn Brand <h.m.br...@xs4all.nl> + - H.Merijn Brand <hmbrand.org> build_requires: Config: 0 configure_requires: @@ -16,7 +16,7 @@ provides: Text::CSV_XS: file: CSV_XS.pm - version: '1.50' + version: '1.51' recommends: Encode: '3.19' requires: @@ -31,4 +31,4 @@ homepage: https://metacpan.org/pod/Text::CSV_XS license: http://dev.perl.org/licenses/ repository: https://github.com/Tux/Text-CSV_XS -version: '1.50' +version: '1.51' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/README new/Text-CSV_XS-1.51/README --- old/Text-CSV_XS-1.50/README 2023-01-03 13:19:01.000000000 +0100 +++ new/Text-CSV_XS-1.51/README 2023-05-30 17:31:32.000000000 +0200 @@ -11,7 +11,7 @@ This distribution provides several examples of scripts that convert CSV files or data streams into XLS or XLSX or simply check if the CSV data is valid. It is easy to amend those scripts to do whatever the end-user - actually requires. The full documentation also provaides various small + actually requires. The full documentation also provides various small snippets of example code. Convert a CSV file into JSON: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/cpanfile new/Text-CSV_XS-1.51/cpanfile --- old/Text-CSV_XS-1.50/cpanfile 2023-03-01 11:54:04.000000000 +0100 +++ new/Text-CSV_XS-1.51/cpanfile 2023-08-07 18:20:02.000000000 +0200 @@ -5,6 +5,8 @@ on "configure" => sub { requires "ExtUtils::MakeMaker"; + + recommends "ExtUtils::MakeMaker" => "7.70"; }; on "build" => sub { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/examples/csvdiff new/Text-CSV_XS-1.51/examples/csvdiff --- old/Text-CSV_XS-1.50/examples/csvdiff 2023-01-03 13:17:23.000000000 +0100 +++ new/Text-CSV_XS-1.51/examples/csvdiff 2023-08-07 13:57:49.000000000 +0200 @@ -1,12 +1,12 @@ #!/pro/bin/perl -use strict; +use 5.012000; use warnings; # csvdiff: Show differences between CSV files -# (m)'19 [05 Mar 2019] Copyright H.M.Brand 2009-2023 +# (m)'23 [05 Aug 2023] Copyright H.M.Brand 2009-2023 -our $VERSION = "1.02 - 20190305"; +our $VERSION = "1.03 - 20230805"; sub usage { my $err = shift and select STDERR; @@ -15,9 +15,9 @@ " assuming first line is header and first field is the key\n", " --no-color do not use colors\n", " -h --html produce HTML output\n", - " -w --ignore-all-space ignore all whistespace is all fields\n", - " -b --ignore-space-change ignore whitespace length changes\n", - " -Z --ignore-trailing-space ignore trailing whitespace per field\n", + " -w --ignore-all-space ignore all white space\n", + " -b --ignore-space-change ignore changes in the amount of white space\n", + " -Z --ignore-trailing-space ignore white space at line end\n", " -o F --output=F send output to file F\n"; exit $err; } # usage @@ -51,14 +51,15 @@ if ($opt_h) { binmode STDOUT, ":encoding(utf-8)"; - print <<EOH; + my $name = $^O eq "MSWin32" ? Win32::LoginName () : scalar getpwuid $<; + print <<"EOH"; <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>CFI School updates</title> <meta name="Generator" content="perl $]" /> - <meta name="Author" content="@{[scalar getpwuid $<]}" /> + <meta name="Author" content="$name" /> <meta name="Description" content="CSV diff @ARGV" /> <style type="text/css"> .rd { background: #ffe0e0; } @@ -99,7 +100,7 @@ my @i = (1, 1); my $hdr = "# csvdiff < $ARGV[0] > $ARGV[1]\n"; -$f[$_][1+$n[$_]][0] = $opt_n ? 2147483647 : "\xff\xff\xff\xff" for 0, 1; +$f[$_][1+$n[$_]][0] = $opt_n ? 0x7FFFFFFF : "\xff\xff\xff\xff" for 0, 1; my %cls; %cls = ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/ppport.h new/Text-CSV_XS-1.51/ppport.h --- old/Text-CSV_XS-1.50/ppport.h 2022-05-24 10:08:04.000000000 +0200 +++ new/Text-CSV_XS-1.51/ppport.h 2023-08-07 09:06:27.000000000 +0200 @@ -4,9 +4,9 @@ /* ---------------------------------------------------------------------- - ppport.h -- Perl/Pollution/Portability Version 3.68 + ppport.h -- Perl/Pollution/Portability Version 3.71 - Automatically created by Devel::PPPort running under perl 5.036000. + Automatically created by Devel::PPPort running under perl 5.038000. Do NOT edit this file directly! -- Edit PPPort_pm.PL and the includes in parts/inc/ instead. @@ -21,7 +21,7 @@ =head1 NAME -ppport.h - Perl/Pollution/Portability version 3.68 +ppport.h - Perl/Pollution/Portability version 3.71 =head1 SYNOPSIS @@ -588,7 +588,7 @@ # Disable broken TRIE-optimization BEGIN { eval '${^RE_TRIE_MAXBUF} = -1' if "$]" >= "5.009004" && "$]" <= "5.009005"} -my $VERSION = 3.68; +my $VERSION = 3.71; my %opt = ( quiet => 0, @@ -5680,7 +5680,6 @@ nextchar|5.005000||Viu NEXT_LINE_CHAR|5.007003||Viu NEXT_OFF|5.005000||Viu -NEXTOPER|5.003007||Viu next_symbol|5.007003||Viu ninstr|5.003007|5.003007|n NL_LANGINFO_LOCK|5.033005||Viu @@ -7733,7 +7732,6 @@ prepare_SV_for_RV|5.010001||Viu prescan_version|5.011004|5.011004| PRESCAN_VERSION|5.019008||Viu -PREVOPER|5.003007||Viu PREV_RANGE_MATCHES_INVLIST|5.023002||Viu printbuf|5.009004||Viu print_bytes_for_locale|5.027002||Viu @@ -8126,6 +8124,8 @@ reg_named_buff_scalar|5.009005||cVu regnext|5.003007||cVu reg_node|5.005000||Viu +REGNODE_AFTER|5.003007||Viu +REGNODE_BEFORE|5.003007||Viu regnode_guts|5.021005||Viu regnode_guts_debug|||Viu REGNODE_MAX|5.009004||Viu @@ -12822,17 +12822,12 @@ #undef STMT_START #undef STMT_END -#if defined(VOIDFLAGS) && defined(PERL_USE_GCC_BRACE_GROUPS) -# define STMT_START (void)( /* gcc supports ``({ STATEMENTS; })'' */ -# define STMT_END ) -#else -# if defined(VOIDFLAGS) && (VOIDFLAGS) && (defined(sun) || defined(__sun__)) && !defined(__GNUC__) +#if defined(VOIDFLAGS) && (VOIDFLAGS) && (defined(sun) || defined(__sun__)) && !defined(__GNUC__) # define STMT_START if (1) # define STMT_END else (void)0 -# else +#else # define STMT_START do # define STMT_END while (0) -# endif #endif #ifndef boolSV # define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no) @@ -15123,17 +15118,18 @@ # else # define D_PPP_FIX_UTF8_ERRSV_FOR_SV(sv) STMT_START {} STMT_END # endif -# define croak_sv(sv) \ - STMT_START { \ - SV *_sv = (sv); \ - if (SvROK(_sv)) { \ - sv_setsv(ERRSV, _sv); \ - croak(NULL); \ - } else { \ - D_PPP_FIX_UTF8_ERRSV_FOR_SV(_sv); \ - croak("%" SVf, SVfARG(_sv)); \ - } \ - } STMT_END +PERL_STATIC_INLINE void D_PPP_croak_sv(SV *sv) { + dTHX; + SV *_sv = (sv); + if (SvROK(_sv)) { + sv_setsv(ERRSV, _sv); + croak(NULL); + } else { + D_PPP_FIX_UTF8_ERRSV_FOR_SV(_sv); + croak("%" SVf, SVfARG(_sv)); + } +} +# define croak_sv(sv) D_PPP_croak_sv(sv) #elif (PERL_BCDVERSION >= 0x5004000) # define croak_sv(sv) croak("%" SVf, SVfARG(sv)) #else @@ -16444,10 +16440,10 @@ #if !defined(sv_unmagicext) #if defined(NEED_sv_unmagicext) -static int DPPP_(my_sv_unmagicext)(pTHX_ SV * const sv, const int type, MGVTBL * vtbl); +static int DPPP_(my_sv_unmagicext)(pTHX_ SV * const sv, const int type, const MGVTBL * vtbl); static #else -extern int DPPP_(my_sv_unmagicext)(pTHX_ SV * const sv, const int type, MGVTBL * vtbl); +extern int DPPP_(my_sv_unmagicext)(pTHX_ SV * const sv, const int type, const MGVTBL * vtbl); #endif #if defined(NEED_sv_unmagicext) || defined(NEED_sv_unmagicext_GLOBAL) @@ -16460,7 +16456,7 @@ int -DPPP_(my_sv_unmagicext)(pTHX_ SV *const sv, const int type, MGVTBL *vtbl) +DPPP_(my_sv_unmagicext)(pTHX_ SV *const sv, const int type, const MGVTBL *vtbl) { MAGIC* mg; MAGIC** mgp; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/t/67_emptrow.t new/Text-CSV_XS-1.51/t/67_emptrow.t --- old/Text-CSV_XS-1.50/t/67_emptrow.t 1970-01-01 01:00:00.000000000 +0100 +++ new/Text-CSV_XS-1.51/t/67_emptrow.t 2023-08-07 15:01:22.000000000 +0200 @@ -0,0 +1,124 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More; + +BEGIN { + if ($] < 5.008001) { + plan skip_all => "This test unit requires perl-5.8.1 or higher"; + } + else { + plan tests => 47; + } + + use_ok "Text::CSV_XS", ("csv"); + plan skip_all => "Cannot load Text::CSV_XS" if $@; + } +my $tfn = "_67test.csv"; END { -f $tfn and unlink $tfn; } + +ok (my $csv = Text::CSV_XS->new, "new"); + +is ($csv->skip_empty_rows, 0, "default"); +is ($csv->skip_empty_rows (1), 1, "+1"); +is ($csv->skip_empty_rows ("skip"), 1, "skip"); +is ($csv->skip_empty_rows ("SKIP"), 1, "SKIP"); +is ($csv->skip_empty_rows (2), "eof", "+2"); +is ($csv->skip_empty_rows ("eof"), "eof", "eof"); +is ($csv->skip_empty_rows ("EOF"), "eof", "EOF"); +is ($csv->skip_empty_rows ("stop"), "eof", "stop"); +is ($csv->skip_empty_rows ("STOP"), "eof", "STOP"); +is ($csv->skip_empty_rows (3), "die", "+3"); +is ($csv->skip_empty_rows ("die"), "die", "die"); +is ($csv->skip_empty_rows ("DIE"), "die", "DIE"); +is ($csv->skip_empty_rows (4), "croak", "+4"); +is ($csv->skip_empty_rows ("croak"), "croak", "croak"); +is ($csv->skip_empty_rows ("CROAK"), "croak", "CROAK"); +is ($csv->skip_empty_rows (5), "error", "+5"); +is ($csv->skip_empty_rows ("error"), "error", "error"); +is ($csv->skip_empty_rows ("ERROR"), "error", "ERROR"); + +sub cba { [ 3, 42, undef, 3 ] } +sub cbh { { a => 3, b => 42, c => undef, d => 3 } } + +is ($csv->skip_empty_rows (\&cba), \&cba, "callback"); + +is ($csv->skip_empty_rows (0), 0, "+0"); +is ($csv->skip_empty_rows (undef), 0, "undef"); + +open my $fh, ">", $tfn; +print $fh "a,b,c,d\n"; +print $fh "1,2,0,4\n"; +print $fh "4,0,9,1\n"; +print $fh "\n"; +print $fh "8,2,7,1\n"; +print $fh "\n"; +print $fh "\n"; +print $fh "5,7,9,3\n"; +print $fh "\n"; +close $fh; + +my @parg = (auto_diag => 0, in => $tfn); +my @head = ([qw( a b c d )], [1,2,0,4], [4,0,9,1]); +my @repl = (1..4); +my $ea = \@repl; + +# Array behavior +is_deeply (csv (@parg, skip_empty_rows => 0), [ @head, + [""],[8,2,7,1],[""],[""],[5,7,9,3],[""]], "A Default"); + +is_deeply (csv (@parg, skip_empty_rows => 1), [ @head, + [8,2,7,1],[5,7,9,3]], "A Skip"); + +is_deeply (csv (@parg, skip_empty_rows => 2), \@head, "A EOF"); + +is (eval { csv (@parg, skip_empty_rows => 3); }, undef, "A die"); +like ($@, qr{^Empty row}, "A msg"); + +is (eval { csv (@parg, skip_empty_rows => 4); }, undef, "A croak"); +like ($@, qr{^Empty row}, "A msg"); + +$@ = ""; +$csv = Text::CSV_XS->new ({ skip_empty_rows => 5 }); +is_deeply ($csv->csv (@parg), \@head, "A error"); +is ($@, "", "A msg"); +is (0 + $csv->error_diag, 2015, "A code"); + +is_deeply (csv (@parg, skip_empty_rows => sub {\@repl}), [ @head, + $ea,[8,2,7,1],$ea,$ea,[5,7,9,3],$ea], "A Callback"); +is_deeply (csv (@parg, skip_empty_rows => sub {0}), \@head, "A Callback 0"); + +# Hash behavior +push @parg => bom => 1; +my $eh = { a => "", b => undef, c => undef, d => undef }, +@head = ({ a => 1, b => 2, c => 0, d => 4 }, + { a => 4, b => 0, c => 9, d => 1 }); +is_deeply (csv (@parg, skip_empty_rows => 0), [ @head, $eh, + { a => 8, b => 2, c => 7, d => 1 },$eh,$eh, + { a => 5, b => 7, c => 9, d => 3 },$eh], "H Default"); + +is_deeply (csv (@parg, skip_empty_rows => 1), [ @head, + { a => 8, b => 2, c => 7, d => 1 }, + { a => 5, b => 7, c => 9, d => 3 }], "H Skip"); + +is_deeply (csv (@parg, skip_empty_rows => 2), \@head, "H EOF"); + +is (eval { csv (@parg, skip_empty_rows => 3); }, undef, "H die"); +like ($@, qr{^Empty row}, "H msg"); + +is (eval { csv (@parg, skip_empty_rows => 4); }, undef, "H croak"); +like ($@, qr{^Empty row}, "H msg"); + +$@ = ""; +$csv = Text::CSV_XS->new ({ skip_empty_rows => 5 }); +is_deeply ($csv->csv (@parg), \@head, "H error"); +is ($@, "", "H msg"); +is (0 + $csv->error_diag, 2015, "H code"); + +$eh = { a => 1, b => 2, c => 3, d => 4 }; +is_deeply (csv (@parg, skip_empty_rows => sub {\@repl}), [ @head, $eh, + { a => 8, b => 2, c => 7, d => 1 },$eh,$eh, + { a => 5, b => 7, c => 9, d => 3 },$eh], "H Callback"); + +is_deeply (csv (@parg, skip_empty_rows => sub {0}), \@head, "H Callback 0"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/t/68_header.t new/Text-CSV_XS-1.51/t/68_header.t --- old/Text-CSV_XS-1.50/t/68_header.t 1970-01-01 01:00:00.000000000 +0100 +++ new/Text-CSV_XS-1.51/t/68_header.t 2023-08-07 15:01:18.000000000 +0200 @@ -0,0 +1,62 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More; + +BEGIN { + if ($] < 5.008001) { + plan skip_all => "This test unit requires perl-5.8.1 or higher"; + } + else { + plan tests => 32; + } + + use_ok "Text::CSV_XS", "csv"; + require "./t/util.pl"; + } + +my $tfn = "_68test.csv"; END { unlink $tfn, "_$tfn"; } + +my @dta = ( + [qw( foo bar zap )], + [qw( mars venus pluto )], + [qw( 1 2 3 )], + ); +my @dth = ( + { foo => "mars", bar => "venus", zap => "pluto" }, + { foo => 1, bar => 2, zap => 3 }, + ); + +{ open my $fh, ">", $tfn or die "$tfn: $!\n"; + local $" = ","; + print $fh "@$_\n" for @dta; + close $fh; + } + +is_deeply (csv (in => $tfn), \@dta, "csv ()"); +is_deeply (csv (in => $tfn, bom => 1), \@dth, "csv (bom)"); +is_deeply (csv (in => $tfn, headers => "auto"), \@dth, "csv (headers)"); +is_deeply (csv (in => $tfn, bom => 1, headers => "auto"), \@dth, "csv (bom, headers)"); + +foreach my $arg ("", "bom", "auto", "bom, auto") { + open my $fh, "<", $tfn or die "$tfn: $!\n"; + my %attr; + $arg =~ m/bom/ and $attr{bom} = 1; + $arg =~ m/auto/ and $attr{headers} = "auto"; + ok (my $csv = Text::CSV_XS->new (), "New ($arg)"); + is ($csv->record_number, 0, "start"); + if ($arg) { + is_deeply ([ $csv->header ($fh, \%attr) ], $dta[0], "Header") if $arg; + is ($csv->record_number, 1, "first data-record"); + is_deeply ($csv->getline_hr ($fh), $dth[$_], "getline $_") for 0..$#dth; + } + else { + is_deeply ($csv->getline ($fh), $dta[$_], "getline $_") for 0..$#dta; + } + is ($csv->record_number, 3, "done"); + close $fh; + } + +done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Text-CSV_XS-1.50/t/80_diag.t new/Text-CSV_XS-1.51/t/80_diag.t --- old/Text-CSV_XS-1.50/t/80_diag.t 2021-03-22 13:20:10.000000000 +0100 +++ new/Text-CSV_XS-1.51/t/80_diag.t 2023-04-04 15:25:58.000000000 +0200 @@ -3,7 +3,7 @@ use strict; use warnings; - use Test::More tests => 335; + use Test::More tests => 345; #use Test::More "no_plan"; my %err; @@ -61,7 +61,7 @@ parse_err 2037, 1, 11, 1, qq{\0 }; { my @warn; - local $SIG{__WARN__} = sub { push @warn, @_ }; + local $SIG{__WARN__} = sub { push @warn => @_ }; $csv->error_diag (); ok (@warn == 1, "Got error message"); like ($warn[0], qr{^# CSV_XS ERROR: 2037 - EIF}, "error content"); @@ -74,26 +74,26 @@ is (Text::CSV_XS->new ({ ecs_char => ":" }), undef, "Unsupported option"); { my @warn; - local $SIG{__WARN__} = sub { push @warn, @_ }; + local $SIG{__WARN__} = sub { push @warn => @_ }; Text::CSV_XS::error_diag (); ok (@warn == 1, "Error_diag in void context ::"); like ($warn[0], qr{^# CSV_XS ERROR: 1000 - INI}, "error content"); } { my @warn; - local $SIG{__WARN__} = sub { push @warn, @_ }; + local $SIG{__WARN__} = sub { push @warn => @_ }; Text::CSV_XS->error_diag (); ok (@warn == 1, "Error_diag in void context ->"); like ($warn[0], qr{^# CSV_XS ERROR: 1000 - INI}, "error content"); } { my @warn; - local $SIG{__WARN__} = sub { push @warn, @_ }; + local $SIG{__WARN__} = sub { push @warn => @_ }; is (Text::CSV_XS->new ({ auto_diag => 0, ecs_char => ":" }), undef, "Unsupported option"); ok (@warn == 0, "Error_diag in from new ({ auto_diag => 0})"); } { my @warn; - local $SIG{__WARN__} = sub { push @warn, @_ }; + local $SIG{__WARN__} = sub { push @warn => @_ }; is (Text::CSV_XS->new ({ auto_diag => 1, ecs_char => ":" }), undef, "Unsupported option"); ok (@warn == 1, "Error_diag in from new ({ auto_diag => 1})"); @@ -116,7 +116,7 @@ ok (1, "Test auto_diag"); $csv = Text::CSV_XS->new ({ auto_diag => 1 }); { my @warn; - local $SIG{__WARN__} = sub { push @warn, @_ }; + local $SIG{__WARN__} = sub { push @warn => @_ }; is ($csv->{_RECNO}, 0, "No records read yet"); is ($csv->parse ('"","'), 0, "1 - bad parse"); ok (@warn == 1, "1 - One error"); @@ -124,7 +124,7 @@ is ($csv->{_RECNO}, 1, "One record read"); } { my @warn; - local $SIG{__WARN__} = sub { push @warn, @_ }; + local $SIG{__WARN__} = sub { push @warn => @_ }; is ($csv->diag_verbose (3), 3, "Set diag_verbose"); is ($csv->parse ('"","'), 0, "1 - bad parse"); ok (@warn == 1, "1 - One error"); @@ -141,7 +141,7 @@ } { my @warn; - local $SIG{__WARN__} = sub { push @warn, @_ }; + local $SIG{__WARN__} = sub { push @warn => @_ }; # Invalid error_input calls is (Text::CSV_XS::error_input (undef), undef, "Bad error_input call"); @@ -299,7 +299,7 @@ is_deeply ($aoh, [{ 1 => 1, 2 => 2, 3 => 3 }], "Column dropped"); my @e; eval { - local $SIG{__WARN__} = sub { push @e, @_ }; + local $SIG{__WARN__} = sub { push @e => @_ }; $aoh = Text::CSV_XS::csv (in => $tfn, headers => "auto", strict => 1); }; is_deeply ($aoh, [], "Fail under strict"); @@ -314,7 +314,7 @@ is_deeply ($aoh, [{ 1 => 1, 2 => 2, 3 => 3, 4 => undef }], "Column added"); @e = (); eval { - local $SIG{__WARN__} = sub { push @e, @_ }; + local $SIG{__WARN__} = sub { push @e => @_ }; $aoh = Text::CSV_XS::csv (in => $tfn, headers => "auto", strict => 1); }; is_deeply ($aoh, [], "Fail under strict"); @@ -339,7 +339,7 @@ } SKIP: { - $] < 5.008 and skip qq{$] does not support ScalarIO}, 14; + $] < 5.008 and skip qq{$] does not support ScalarIO}, 24; foreach my $key ({}, sub {}, []) { my $csv = Text::CSV_XS->new; my $x = eval { $csv->csv (in => \"a,b", key => $key) }; @@ -362,6 +362,17 @@ my @diag = $csv->error_diag; is ($diag[0], 1503, "Invalid value type"); } + + foreach my $ser ("die", 4) { + ok (my $csv = Text::CSV_XS->new ({ skip_empty_rows => $ser }), + "New CSV for SER $ser"); + is (eval { $csv->csv (in => \"\n") }, undef, + "Parse empty line for SER $ser"); + like ($@, qr{^Empty row}, "Message"); + my @diag = $csv->error_diag; + is ($diag[0], 2015, "Empty row"); + like ($diag[1], qr{^ERW - Empty row}, "Error description"); + } } # Issue 19: auto_diag > 1 does not die if ->header () is used @@ -378,8 +389,8 @@ my $ok = eval { open $fh, "<", $tfn or die "$tfn: $!\n"; my $csv = Text::CSV_XS->new ({ auto_diag => 2 }); - $h and push @row, [ $csv->header ($fh) ]; - while (my $row = $csv->getline ($fh)) { push @row, $row } + $h and push @row => [ $csv->header ($fh) ]; + while (my $row = $csv->getline ($fh)) { push @row => $row } close $fh; 1; };